blob: 2fb2f36ec9912cb520ff198e43e923389e66b669 [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.VirtualDeviceManager.DEVICE_ID_DEFAULT;
20import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
21import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
22
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080023import android.annotation.CallbackExecutor;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080024import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070025import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080026import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070027import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060028import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.annotation.SdkConstant;
30import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070031import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090032import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060033import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070034import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050035import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070036import android.app.PendingIntent;
Eric Laurent1c3408f2021-11-09 12:09:54 +010037import android.app.compat.CompatChanges;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080038import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070039import android.bluetooth.BluetoothDevice;
Patty46694212021-11-04 21:03:32 +080040import android.bluetooth.BluetoothLeAudioCodecConfig;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010041import android.companion.virtual.VirtualDeviceManager;
Eric Laurent1c3408f2021-11-09 12:09:54 +010042import android.compat.annotation.ChangeId;
43import android.compat.annotation.EnabledSince;
Artur Satayev53fe9662019-12-10 17:47:55 +000044import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070045import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070047import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080048import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080049import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070050import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080051import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070052import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070053import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020054import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080055import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070056import android.media.session.MediaController;
57import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070058import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070059import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070060import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070062import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.Handler;
64import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080065import android.os.Looper;
66import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.os.RemoteException;
68import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050069import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010070import android.os.UserHandle;
Lais Andrade724d0cd2021-11-03 19:46:21 +000071import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080072import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070073import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080075import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070076import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080078import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020079import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080080
jiabinc0f49442018-01-05 10:23:50 -080081import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080082import java.lang.annotation.Retention;
83import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070084import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080085import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070086import java.util.Arrays;
Dorin Drimusdaeb6a92021-12-22 11:46:26 +010087import java.util.Collections;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080088import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070089import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090090import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080091import java.util.List;
jiabin39940752018-04-02 18:18:45 -070092import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070093import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090094import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070095import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080096import java.util.concurrent.Executor;
Eric Laurent78eef3a2021-11-09 16:10:42 +010097import java.util.concurrent.Executors;
Jean-Michel Trivi933bf142021-11-19 16:18:52 -080098import java.util.concurrent.TimeUnit;
Eric Laurent700e7342014-05-02 18:33:15 -070099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100/**
101 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600103@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104public class AudioManager {
105
Marco Nelissen29f16932015-04-17 09:50:56 -0700106 private Context mOriginalContext;
107 private Context mApplicationContext;
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000108 private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100109 private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized.
Joe Onorato86f67862010-11-05 18:57:34 -0700110 private long mVolumeKeyUpTime;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800111 private static final String TAG = "AudioManager";
112 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800113 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200114 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
115 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
jiabin0f3339c2021-07-09 11:50:07 -0700117 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 /**
120 * Broadcast intent, a hint for applications that audio is about to become
121 * 'noisy' due to a change in audio outputs. For example, this intent may
122 * be sent when a wired headset is unplugged, or when an A2DP audio
123 * sink is disconnected, and the audio system is about to automatically
124 * switch audio route to the speaker. Applications that are controlling
125 * audio streams may consider pausing, reducing volume or some other action
126 * on receipt of this intent so as not to surprise the user with audio
127 * from the speaker.
128 */
129 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
130 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
131
132 /**
133 * Sticky broadcast intent action indicating that the ringer mode has
134 * changed. Includes the new ringer mode.
135 *
136 * @see #EXTRA_RINGER_MODE
137 */
138 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
139 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
140
141 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500142 * @hide
143 * Sticky broadcast intent action indicating that the internal ringer mode has
144 * changed. Includes the new ringer mode.
145 *
146 * @see #EXTRA_RINGER_MODE
147 */
148 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
149 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
150 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
151
152 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 * The new ringer mode.
154 *
155 * @see #RINGER_MODE_CHANGED_ACTION
156 * @see #RINGER_MODE_NORMAL
157 * @see #RINGER_MODE_SILENT
158 * @see #RINGER_MODE_VIBRATE
159 */
160 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
161
162 /**
163 * Broadcast intent action indicating that the vibrate setting has
164 * changed. Includes the vibrate type and its new setting.
165 *
166 * @see #EXTRA_VIBRATE_TYPE
167 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700168 * @deprecated Applications should maintain their own vibrate policy based on
169 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 */
171 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500172 public static final String VIBRATE_SETTING_CHANGED_ACTION =
173 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
175 /**
176 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700177 * Includes the stream, the new volume and previous volumes.
178 * Notes:
179 * - for internal platform use only, do not make public,
180 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 *
182 * @see #EXTRA_VOLUME_STREAM_TYPE
183 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800184 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 */
186 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100187 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
189
190 /**
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800191 * @hide Broadcast intent when the volume for a particular stream type changes.
192 * Includes the stream, the new volume and previous volumes.
193 * Notes:
194 * - for internal platform use only, do not make public,
195 * - never used for "remote" volume changes
196 *
197 * @see #EXTRA_VOLUME_STREAM_TYPE
198 * @see #EXTRA_VOLUME_STREAM_VALUE
199 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
200 */
201 @SystemApi
202 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
203 @SuppressLint("ActionValue")
204 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
205
206 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400207 * @hide Broadcast intent when the devices for a particular stream type changes.
208 * Includes the stream, the new devices and previous devices.
209 * Notes:
210 * - for internal platform use only, do not make public,
211 * - never used for "remote" volume changes
212 *
213 * @see #EXTRA_VOLUME_STREAM_TYPE
214 * @see #EXTRA_VOLUME_STREAM_DEVICES
215 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
216 * @see #getDevicesForStream
217 */
218 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
219 public static final String STREAM_DEVICES_CHANGED_ACTION =
220 "android.media.STREAM_DEVICES_CHANGED_ACTION";
221
222 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800223 * @hide Broadcast intent when a stream mute state changes.
224 * Includes the stream that changed and the new mute state
225 *
226 * @see #EXTRA_VOLUME_STREAM_TYPE
227 * @see #EXTRA_STREAM_VOLUME_MUTED
228 */
229 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
230 public static final String STREAM_MUTE_CHANGED_ACTION =
231 "android.media.STREAM_MUTE_CHANGED_ACTION";
232
233 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500234 * @hide Broadcast intent when the master mute state changes.
235 * Includes the the new volume
236 *
237 * @see #EXTRA_MASTER_VOLUME_MUTED
238 */
239 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
240 public static final String MASTER_MUTE_CHANGED_ACTION =
241 "android.media.MASTER_MUTE_CHANGED_ACTION";
242
243 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 * The new vibrate setting for a particular type.
245 *
246 * @see #VIBRATE_SETTING_CHANGED_ACTION
247 * @see #EXTRA_VIBRATE_TYPE
248 * @see #VIBRATE_SETTING_ON
249 * @see #VIBRATE_SETTING_OFF
250 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700251 * @deprecated Applications should maintain their own vibrate policy based on
252 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 */
254 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
255
256 /**
257 * The vibrate type whose setting has changed.
258 *
259 * @see #VIBRATE_SETTING_CHANGED_ACTION
260 * @see #VIBRATE_TYPE_NOTIFICATION
261 * @see #VIBRATE_TYPE_RINGER
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_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
266
267 /**
268 * @hide The stream type for the volume changed intent.
269 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800270 @SystemApi
271 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
273
274 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700275 * @hide
276 * The stream type alias for the volume changed intent.
277 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
278 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
279 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
280 * {@link #STREAM_MUSIC} on others (e.g. a television).
281 */
282 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
283 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
284
285 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 * @hide The volume associated with the stream for the volume changed intent.
287 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800288 @SystemApi
289 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 public static final String EXTRA_VOLUME_STREAM_VALUE =
291 "android.media.EXTRA_VOLUME_STREAM_VALUE";
292
Eric Laurent9ce379a2010-02-16 06:00:26 -0800293 /**
294 * @hide The previous volume associated with the stream for the volume changed intent.
295 */
296 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
297 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
298
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500299 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400300 * @hide The devices associated with the stream for the stream devices changed intent.
301 */
302 public static final String EXTRA_VOLUME_STREAM_DEVICES =
303 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
304
305 /**
306 * @hide The previous devices associated with the stream for the stream devices changed intent.
307 */
308 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
309 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
310
311 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500312 * @hide The new master volume mute state for the master mute changed intent.
313 * Value is boolean
314 */
315 public static final String EXTRA_MASTER_VOLUME_MUTED =
316 "android.media.EXTRA_MASTER_VOLUME_MUTED";
317
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700318 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800319 * @hide The new stream volume mute state for the stream mute changed intent.
320 * Value is boolean
321 */
322 public static final String EXTRA_STREAM_VOLUME_MUTED =
323 "android.media.EXTRA_STREAM_VOLUME_MUTED";
324
325 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700326 * Broadcast Action: Wired Headset plugged in or unplugged.
327 *
328 * You <em>cannot</em> receive this through components declared
329 * in manifests, only by explicitly registering for it with
330 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
331 * Context.registerReceiver()}.
332 *
333 * <p>The intent will have the following extra values:
334 * <ul>
335 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
336 * <li><em>name</em> - Headset type, human readable string </li>
337 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
338 * </ul>
339 * </ul>
340 */
341 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
342 public static final String ACTION_HEADSET_PLUG =
343 "android.intent.action.HEADSET_PLUG";
344
345 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200346 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700347 *
348 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
349 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
350 * <p>It can only be received by explicitly registering for it with
351 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
352 */
353 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
354 public static final String ACTION_HDMI_AUDIO_PLUG =
355 "android.media.action.HDMI_AUDIO_PLUG";
356
357 /**
358 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
359 * or unplugged.
360 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
361 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700362 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700363
364 /**
365 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
366 * supported by the HDMI device.
367 * The corresponding integer value is only available when the device is plugged in (as expressed
368 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
369 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700370 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700371
372 /**
373 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
374 * the connected HDMI device.
375 * The corresponding array of encoding values is only available when the device is plugged in
376 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
377 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
378 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
379 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700380 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700381
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700382 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700384 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700386 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700388 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700390 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700392 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700394 /** @hide Used to identify the volume of audio streams for phone calls when connected
395 * to bluetooth */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800396 @SystemApi
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700398 /** @hide Used to identify the volume of audio streams for enforced system sounds
399 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100400 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700401 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700402 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700403 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700404 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
405 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100406 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700407 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800408 /** Used to identify the volume of audio streams for accessibility prompts */
409 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000410 /** @hide Used to identify the volume of audio streams for virtual assistant */
411 @SystemApi
412 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
413 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 /** Number of audio streams */
416 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700417 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 */
Eric Laurenta553c252009-07-17 12:17:14 -0700419 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420
Paul McLeand6f87c82021-03-31 13:02:41 -0600421 /** @hide */
422 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
423 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
424 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
425 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
426
427 /** @hide */
428 @TestApi
429 public static final int[] getPublicStreamTypes() {
430 return PUBLIC_STREAM_TYPES;
431 }
432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 /**
434 * Increase the ringer volume.
435 *
436 * @see #adjustVolume(int, int)
437 * @see #adjustStreamVolume(int, int, int)
438 */
439 public static final int ADJUST_RAISE = 1;
440
441 /**
442 * Decrease the ringer volume.
443 *
444 * @see #adjustVolume(int, int)
445 * @see #adjustStreamVolume(int, int, int)
446 */
447 public static final int ADJUST_LOWER = -1;
448
449 /**
450 * Maintain the previous ringer volume. This may be useful when needing to
451 * show the volume toast without actually modifying the volume.
452 *
453 * @see #adjustVolume(int, int)
454 * @see #adjustStreamVolume(int, int, int)
455 */
456 public static final int ADJUST_SAME = 0;
457
RoboErik4197cb62015-01-21 15:45:32 -0800458 /**
459 * Mute the volume. Has no effect if the stream is already muted.
460 *
461 * @see #adjustVolume(int, int)
462 * @see #adjustStreamVolume(int, int, int)
463 */
464 public static final int ADJUST_MUTE = -100;
465
466 /**
467 * Unmute the volume. Has no effect if the stream is not muted.
468 *
469 * @see #adjustVolume(int, int)
470 * @see #adjustStreamVolume(int, int, int)
471 */
472 public static final int ADJUST_UNMUTE = 100;
473
474 /**
475 * Toggle the mute state. If muted the stream will be unmuted. If not muted
476 * the stream will be muted.
477 *
478 * @see #adjustVolume(int, int)
479 * @see #adjustStreamVolume(int, int, int)
480 */
481 public static final int ADJUST_TOGGLE_MUTE = 101;
482
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700483 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800484 @IntDef(flag = false, prefix = "ADJUST", value = {
485 ADJUST_RAISE,
486 ADJUST_LOWER,
487 ADJUST_SAME,
488 ADJUST_MUTE,
489 ADJUST_UNMUTE,
490 ADJUST_TOGGLE_MUTE }
491 )
492 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800493 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800494
495 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700496 public static final String adjustToString(int adj) {
497 switch (adj) {
498 case ADJUST_RAISE: return "ADJUST_RAISE";
499 case ADJUST_LOWER: return "ADJUST_LOWER";
500 case ADJUST_SAME: return "ADJUST_SAME";
501 case ADJUST_MUTE: return "ADJUST_MUTE";
502 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
503 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
504 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
505 }
506 }
507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 // Flags should be powers of 2!
509
510 /**
511 * Show a toast containing the current volume.
512 *
513 * @see #adjustStreamVolume(int, int, int)
514 * @see #adjustVolume(int, int)
515 * @see #setStreamVolume(int, int, int)
516 * @see #setRingerMode(int)
517 */
518 public static final int FLAG_SHOW_UI = 1 << 0;
519
520 /**
521 * Whether to include ringer modes as possible options when changing volume.
522 * For example, if true and volume level is 0 and the volume is adjusted
523 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
524 * vibrate mode.
525 * <p>
526 * By default this is on for the ring stream. If this flag is included,
527 * this behavior will be present regardless of the stream type being
528 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700529 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 * @see #adjustVolume(int, int)
531 * @see #adjustStreamVolume(int, int, int)
532 */
533 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
534
535 /**
536 * Whether to play a sound when changing the volume.
537 * <p>
538 * If this is given to {@link #adjustVolume(int, int)} or
539 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
540 * in some cases (for example, the decided stream type is not
541 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
542 * downward).
543 *
544 * @see #adjustStreamVolume(int, int, int)
545 * @see #adjustVolume(int, int)
546 * @see #setStreamVolume(int, int, int)
547 */
548 public static final int FLAG_PLAY_SOUND = 1 << 2;
549
550 /**
551 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
552 * changing volume).
553 */
554 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
555
556 /**
557 * Whether to vibrate if going into the vibrate ringer mode.
558 */
559 public static final int FLAG_VIBRATE = 1 << 4;
560
561 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700562 * Indicates to VolumePanel that the volume slider should be disabled as user
563 * cannot change the stream volume
564 * @hide
565 */
566 public static final int FLAG_FIXED_VOLUME = 1 << 5;
567
568 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700569 * Indicates the volume set/adjust call is for Bluetooth absolute volume
570 * @hide
571 */
Roopa Sattirajufb933242022-01-30 13:27:58 -0800572 @SystemApi
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700573 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
574
575 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400576 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
577 * @hide
578 */
579 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
580
581 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900582 * Indicates the volume call is for Hdmi Cec system audio volume
583 * @hide
584 */
585 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
586
587 /**
RoboErik3c45c292014-07-08 16:47:31 -0700588 * Indicates that this should only be handled if media is actively playing.
589 * @hide
590 */
591 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
592
593 /**
John Spurlock35134602014-07-24 18:10:48 -0400594 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
595 * @hide
596 */
597 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
598
599 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500600 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
601 * @hide
602 */
603 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
604
John Spurlockb94f2d62015-03-17 14:11:57 -0400605 /**
606 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900607 * This flag can be used in the places in order to denote (or check) that a volume adjustment
608 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400609 * @hide
610 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900611 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900612 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400613
Yan Han7d419822022-01-31 19:10:16 +0100614 /**
615 * Indicates that an absolute volume controller is notifying AudioService of a change in the
616 * volume or mute status of an external audio system.
617 * @hide
618 */
619 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
620
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900621 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100622 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200623 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100624 ENCODED_SURROUND_OUTPUT_AUTO,
625 ENCODED_SURROUND_OUTPUT_NEVER,
626 ENCODED_SURROUND_OUTPUT_ALWAYS,
627 ENCODED_SURROUND_OUTPUT_MANUAL
628 })
629 @Retention(RetentionPolicy.SOURCE)
630 public @interface EncodedSurroundOutputMode {}
631
632 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200633 * The mode for surround sound formats is unknown.
634 */
635 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
636
637 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100638 * The surround sound formats are available for use if they are detected. This is the default
639 * mode.
640 */
641 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
642
643 /**
644 * The surround sound formats are NEVER available, even if they are detected by the hardware.
645 * Those formats will not be reported.
646 */
647 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
648
649 /**
650 * The surround sound formats are ALWAYS available, even if they are not detected by the
651 * hardware. Those formats will be reported as part of the HDMI output capability.
652 * Applications are then free to use either PCM or encoded output.
653 */
654 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
655
656 /**
657 * Surround sound formats are available according to the choice of user, even if they are not
658 * detected by the hardware. Those formats will be reported as part of the HDMI output
659 * capability. Applications are then free to use either PCM or encoded output.
660 */
661 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
662
663 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900664 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900665 FLAG_SHOW_UI,
666 FLAG_ALLOW_RINGER_MODES,
667 FLAG_PLAY_SOUND,
668 FLAG_REMOVE_SOUND_AND_VIBRATE,
669 FLAG_VIBRATE,
670 FLAG_FIXED_VOLUME,
671 FLAG_BLUETOOTH_ABS_VOLUME,
672 FLAG_SHOW_SILENT_HINT,
673 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
674 FLAG_ACTIVE_MEDIA_ONLY,
675 FLAG_SHOW_UI_WARNINGS,
676 FLAG_SHOW_VIBRATE_HINT,
677 FLAG_FROM_KEY,
Yan Han7d419822022-01-31 19:10:16 +0100678 FLAG_ABSOLUTE_VOLUME,
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900679 })
680 @Retention(RetentionPolicy.SOURCE)
681 public @interface Flags {}
682
Hyundo Moonca0080d2018-12-26 16:16:55 +0900683 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
684 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
685
686 static {
687 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
688 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
689 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
690 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
691 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
692 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
693 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
694 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
695 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
696 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
697 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
698 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
699 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
Yan Han7d419822022-01-31 19:10:16 +0100700 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
Hyundo Moonca0080d2018-12-26 16:16:55 +0900701 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500702
703 /** @hide */
704 public static String flagsToString(int flags) {
705 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900706 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
707 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500708 if ((flags & flag) != 0) {
709 if (sb.length() > 0) {
710 sb.append(',');
711 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900712 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500713 flags &= ~flag;
714 }
715 }
716 if (flags != 0) {
717 if (sb.length() > 0) {
718 sb.append(',');
719 }
720 sb.append(flags);
721 }
722 return sb.toString();
723 }
724
725 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 * Ringer mode that will be silent and will not vibrate. (This overrides the
727 * vibrate setting.)
728 *
729 * @see #setRingerMode(int)
730 * @see #getRingerMode()
731 */
732 public static final int RINGER_MODE_SILENT = 0;
733
734 /**
735 * Ringer mode that will be silent and will vibrate. (This will cause the
736 * phone ringer to always vibrate, but the notification vibrate to only
737 * vibrate if set.)
738 *
739 * @see #setRingerMode(int)
740 * @see #getRingerMode()
741 */
742 public static final int RINGER_MODE_VIBRATE = 1;
743
744 /**
745 * Ringer mode that may be audible and may vibrate. It will be audible if
746 * the volume before changing out of this mode was audible. It will vibrate
747 * if the vibrate setting is on.
748 *
749 * @see #setRingerMode(int)
750 * @see #getRingerMode()
751 */
752 public static final int RINGER_MODE_NORMAL = 2;
753
John Spurlock97559372014-10-24 16:27:36 -0400754 /**
755 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
756 * @hide
757 */
758 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 /**
761 * Vibrate type that corresponds to the ringer.
762 *
763 * @see #setVibrateSetting(int, int)
764 * @see #getVibrateSetting(int)
765 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700766 * @deprecated Applications should maintain their own vibrate policy based on
767 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 */
769 public static final int VIBRATE_TYPE_RINGER = 0;
770
771 /**
772 * Vibrate type that corresponds to notifications.
773 *
774 * @see #setVibrateSetting(int, int)
775 * @see #getVibrateSetting(int)
776 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700777 * @deprecated Applications should maintain their own vibrate policy based on
778 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 */
780 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
781
782 /**
783 * Vibrate setting that suggests to never vibrate.
784 *
785 * @see #setVibrateSetting(int, int)
786 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700787 * @deprecated Applications should maintain their own vibrate policy based on
788 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 */
790 public static final int VIBRATE_SETTING_OFF = 0;
791
792 /**
793 * Vibrate setting that suggests to vibrate when possible.
794 *
795 * @see #setVibrateSetting(int, int)
796 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700797 * @deprecated Applications should maintain their own vibrate policy based on
798 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 */
800 public static final int VIBRATE_SETTING_ON = 1;
801
802 /**
803 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
804 * mode.
805 *
806 * @see #setVibrateSetting(int, int)
807 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700808 * @deprecated Applications should maintain their own vibrate policy based on
809 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 */
811 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
812
813 /**
814 * Suggests using the default stream type. This may not be used in all
815 * places a stream type is needed.
816 */
817 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
818
819 private static IAudioService sService;
820
821 /**
822 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800823 * For test purposes only, will throw NPE with some methods that require a Context.
824 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000825 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800826 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800827 }
828
829 /**
830 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100832 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700834 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 }
836
Marco Nelissen29f16932015-04-17 09:50:56 -0700837 private Context getContext() {
838 if (mApplicationContext == null) {
839 setContext(mOriginalContext);
840 }
841 if (mApplicationContext != null) {
842 return mApplicationContext;
843 }
844 return mOriginalContext;
845 }
846
847 private void setContext(Context context) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000848 mOriginalContextDeviceId = context.getDeviceId();
Marco Nelissen29f16932015-04-17 09:50:56 -0700849 mApplicationContext = context.getApplicationContext();
850 if (mApplicationContext != null) {
851 mOriginalContext = null;
852 } else {
853 mOriginalContext = context;
854 }
jiabin0f3339c2021-07-09 11:50:07 -0700855 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700856 }
857
Mathew Inwood31a792a2018-08-17 08:54:26 +0100858 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700859 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 {
861 if (sService != null) {
862 return sService;
863 }
864 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
865 sService = IAudioService.Stub.asInterface(b);
866 return sService;
867 }
868
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100869 private VirtualDeviceManager getVirtualDeviceManager() {
870 if (mVirtualDeviceManager != null) {
871 return mVirtualDeviceManager;
872 }
873 mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class);
874 return mVirtualDeviceManager;
875 }
876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700878 * Sends a simulated key event for a media button.
879 * To simulate a key press, you must first send a KeyEvent built with a
880 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
881 * action.
882 * <p>The key event will be sent to the current media key event consumer which registered with
883 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
884 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
885 * {@link KeyEvent#KEYCODE_MUTE},
886 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
887 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
888 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
889 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
890 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
891 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
892 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
893 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
894 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
895 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
896 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
897 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
898 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700899 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700900 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700901 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700902 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700903 }
904
905 /**
906 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700907 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800908 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700909 /*
910 * If the user hits another key within the play sound delay, then
911 * cancel the sound
912 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800913 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700914 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
915 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500916 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700917 /*
918 * The user has hit another key during the delay (e.g., 300ms)
919 * since the last volume key up, so cancel any sounds.
920 */
John Spurlockee5ad722015-03-03 16:17:21 -0500921 adjustSuggestedStreamVolume(ADJUST_SAME,
922 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700923 }
924 }
925
926 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700927 * Indicates if the device implements a fixed volume policy.
928 * <p>Some devices may not have volume control and may operate at a fixed volume,
929 * and may not enable muting or changing the volume of audio streams.
930 * This method will return true on such devices.
931 * <p>The following APIs have no effect when volume is fixed:
932 * <ul>
933 * <li> {@link #adjustVolume(int, int)}
934 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
935 * <li> {@link #adjustStreamVolume(int, int, int)}
936 * <li> {@link #setStreamVolume(int, int, int)}
937 * <li> {@link #setRingerMode(int)}
938 * <li> {@link #setStreamSolo(int, boolean)}
939 * <li> {@link #setStreamMute(int, boolean)}
940 * </ul>
941 */
942 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700943 boolean res = false;
944 try {
945 res = getService().isVolumeFixed();
946 } catch (RemoteException e) {
947 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700948 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700949 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700950 }
951
952 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700954 * <p>
955 * This method should only be used by applications that replace the platform-wide
956 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700957 * <p>This method has no effect if the device implements a fixed volume policy
958 * as indicated by {@link #isVolumeFixed()}.
959 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
960 * unless the app has been granted Do Not Disturb Access.
961 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 *
963 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800964 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
965 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 * @param direction The direction to adjust the volume. One of
967 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
968 * {@link #ADJUST_SAME}.
969 * @param flags One or more flags.
970 * @see #adjustVolume(int, int)
971 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700972 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
973 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 */
975 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700976 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 try {
John Wu4f7e5102021-06-22 17:29:11 +0000978 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
979 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700981 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 }
983 }
984
985 /**
986 * Adjusts the volume of the most relevant stream. For example, if a call is
987 * active, it will have the highest priority regardless of if the in-call
988 * screen is showing. Another example, if music is playing in the background
989 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700990 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800991 * This method should only be used by applications that replace the
992 * platform-wide management of audio settings or the main telephony
993 * application.
994 * <p>
995 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700996 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800997 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800999 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1000 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1001 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 * @param flags One or more flags.
1003 * @see #adjustSuggestedStreamVolume(int, int, int)
1004 * @see #adjustStreamVolume(int, int, int)
1005 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001006 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 */
1008 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001009 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001010 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 }
1012
1013 /**
1014 * Adjusts the volume of the most relevant stream, or the given fallback
1015 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001016 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001017 * This method should only be used by applications that replace the
1018 * platform-wide management of audio settings or the main telephony
1019 * application.
1020 * <p>
1021 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001022 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001023 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001025 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1026 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1027 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001029 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1030 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 * @param flags One or more flags.
1032 * @see #adjustVolume(int, int)
1033 * @see #adjustStreamVolume(int, int, int)
1034 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001035 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 */
1037 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001038 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001039 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001040 }
1041
John Spurlockee5ad722015-03-03 16:17:21 -05001042 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001043 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -07001044 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001045 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001046 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001047 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001048 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001049 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001050 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001051 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053 }
1054
1055 /**
1056 * Returns the current ringtone mode.
1057 *
1058 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1059 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1060 * @see #setRingerMode(int)
1061 */
1062 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001063 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001065 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001067 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 }
1069 }
1070
1071 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001072 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1073 *
1074 * @return true if the incoming phone call ringtone is configured to gradually increase its
1075 * volume, false otherwise.
1076 */
1077 public boolean isRampingRingerEnabled() {
1078 return Settings.System.getInt(getContext().getContentResolver(),
1079 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1080 }
1081
1082 /**
1083 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1084 *
1085 * @see #isRampingRingerEnabled()
1086 * @hide
1087 */
1088 @TestApi
1089 public void setRampingRingerEnabled(boolean enabled) {
1090 Settings.System.putInt(getContext().getContentResolver(),
1091 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1092 }
1093
1094 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001095 * Checks valid ringer mode values.
1096 *
1097 * @return true if the ringer mode indicated is valid, false otherwise.
1098 *
1099 * @see #setRingerMode(int)
1100 * @hide
1101 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001102 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001103 public static boolean isValidRingerMode(int ringerMode) {
1104 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1105 return false;
1106 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001107 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001108 try {
1109 return service.isValidRingerMode(ringerMode);
1110 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001111 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001112 }
Eric Laurent72668b22011-07-19 16:04:27 -07001113 }
1114
1115 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 * Returns the maximum volume index for a particular stream.
1117 *
1118 * @param streamType The stream type whose maximum volume index is returned.
1119 * @return The maximum valid volume index for the stream.
1120 * @see #getStreamVolume(int)
1121 */
1122 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001123 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001125 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001127 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129 }
1130
1131 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001132 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001133 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1134 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1135 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1136 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1137 * @return The minimum valid volume index for the stream.
1138 * @see #getStreamVolume(int)
1139 */
1140 public int getStreamMinVolume(int streamType) {
1141 if (!isPublicStreamType(streamType)) {
1142 throw new IllegalArgumentException("Invalid stream type " + streamType);
1143 }
1144 return getStreamMinVolumeInt(streamType);
1145 }
1146
1147 /**
1148 * @hide
1149 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001150 * @param streamType The stream type whose minimum volume index is returned.
1151 * @return The minimum valid volume index for the stream.
1152 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001153 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001154 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001155 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001156 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001157 try {
1158 return service.getStreamMinVolume(streamType);
1159 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001160 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001161 }
1162 }
1163
1164 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 * Returns the current volume index for a particular stream.
1166 *
1167 * @param streamType The stream type whose volume index is returned.
1168 * @return The current volume index for the stream.
1169 * @see #getStreamMaxVolume(int)
1170 * @see #setStreamVolume(int, int, int)
1171 */
1172 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001173 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001175 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001177 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 }
1179 }
1180
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001181 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1182 private static final float VOLUME_MIN_DB = -758.0f;
1183
1184 /** @hide */
1185 @IntDef(flag = false, prefix = "STREAM", value = {
1186 STREAM_VOICE_CALL,
1187 STREAM_SYSTEM,
1188 STREAM_RING,
1189 STREAM_MUSIC,
1190 STREAM_ALARM,
1191 STREAM_NOTIFICATION,
1192 STREAM_DTMF,
1193 STREAM_ACCESSIBILITY }
1194 )
1195 @Retention(RetentionPolicy.SOURCE)
1196 public @interface PublicStreamTypes {}
1197
1198 /**
1199 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1200 * the given type of audio output device.
1201 * @param streamType stream type for which the volume is queried.
1202 * @param index the volume index for which the volume is queried. The index value must be
1203 * between the minimum and maximum index values for the given stream type (see
1204 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1205 * @param deviceType the type of audio output device for which volume is queried.
1206 * @return a volume expressed in dB.
1207 * A negative value indicates the audio signal is attenuated. A typical maximum value
1208 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1209 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1210 */
1211 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1212 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1213 if (!isPublicStreamType(streamType)) {
1214 throw new IllegalArgumentException("Invalid stream type " + streamType);
1215 }
1216 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1217 throw new IllegalArgumentException("Invalid stream volume index " + index);
1218 }
1219 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1220 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1221 }
1222 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1223 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1224 if (gain <= VOLUME_MIN_DB) {
1225 return Float.NEGATIVE_INFINITY;
1226 } else {
1227 return gain;
1228 }
1229 }
1230
Jean-Michel Trivi283a4c72022-09-28 21:46:51 +00001231 /**
1232 * @hide
1233 * Checks whether a stream type is part of the public SDK
1234 * @param streamType
1235 * @return true if the stream type is available in SDK
1236 */
1237 public static boolean isPublicStreamType(int streamType) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001238 switch (streamType) {
1239 case STREAM_VOICE_CALL:
1240 case STREAM_SYSTEM:
1241 case STREAM_RING:
1242 case STREAM_MUSIC:
1243 case STREAM_ALARM:
1244 case STREAM_NOTIFICATION:
1245 case STREAM_DTMF:
1246 case STREAM_ACCESSIBILITY:
1247 return true;
1248 default:
1249 return false;
1250 }
1251 }
1252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001254 * Get last audible volume before stream was muted.
1255 *
1256 * @hide
1257 */
wescandee178f8f2021-10-19 20:15:09 +02001258 @SystemApi
1259 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001260 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001261 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001262 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001263 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001264 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001265 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001266 }
1267 }
1268
1269 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001270 * Get the stream type whose volume is driving the UI sounds volume.
1271 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001272 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001273 * @hide
1274 */
John Spurlockee5ad722015-03-03 16:17:21 -05001275 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001276 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001277 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001278 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001279 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001280 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001281 }
1282 }
1283
1284 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 * Sets the ringer mode.
1286 * <p>
1287 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1288 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1289 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001290 * <p>This method has no effect if the device implements a fixed volume policy
1291 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001292 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1293 * unless the app has been granted Do Not Disturb Access.
1294 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1296 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1297 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001298 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 */
1300 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001301 if (!isValidRingerMode(ringerMode)) {
1302 return;
1303 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001304 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001306 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001308 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
1310 }
1311
1312 /**
1313 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001314 * <p>This method has no effect if the device implements a fixed volume policy
1315 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001316 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1317 * the app has been granted Do Not Disturb Access.
1318 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 * @param streamType The stream whose volume index should be set.
1320 * @param index The volume index to set. See
1321 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1322 * @param flags One or more flags.
1323 * @see #getStreamMaxVolume(int)
1324 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001325 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001326 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1327 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 */
1329 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001330 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 try {
John Wu4f7e5102021-06-22 17:29:11 +00001332 service.setStreamVolumeWithAttribution(streamType, index, flags,
1333 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001335 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 }
1337 }
1338
1339 /**
François Gaffie9c362102018-09-21 17:43:52 +02001340 * Sets the volume index for a particular {@link AudioAttributes}.
1341 * @param attr The {@link AudioAttributes} whose volume index should be set.
1342 * @param index The volume index to set. See
1343 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1344 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1345 * @param flags One or more flags.
1346 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1347 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1348 * @see #isVolumeFixed()
1349 * @hide
1350 */
1351 @SystemApi
1352 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1353 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1354 Preconditions.checkNotNull(attr, "attr must not be null");
1355 final IAudioService service = getService();
1356 try {
1357 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001358 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001359 } catch (RemoteException e) {
1360 throw e.rethrowFromSystemServer();
1361 }
1362 }
1363
1364 /**
1365 * Returns the current volume index for a particular {@link AudioAttributes}.
1366 *
1367 * @param attr The {@link AudioAttributes} whose volume index is returned.
1368 * @return The current volume index for the stream.
1369 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1370 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1371 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1372 * @hide
1373 */
1374 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001375 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001376 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1377 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1378 Preconditions.checkNotNull(attr, "attr must not be null");
1379 final IAudioService service = getService();
1380 try {
1381 return service.getVolumeIndexForAttributes(attr);
1382 } catch (RemoteException e) {
1383 throw e.rethrowFromSystemServer();
1384 }
1385 }
1386
1387 /**
1388 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1389 *
1390 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1391 * @return The maximum valid volume index for the {@link AudioAttributes}.
1392 * @see #getVolumeIndexForAttributes(AudioAttributes)
1393 * @hide
1394 */
1395 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001396 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001397 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1398 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1399 Preconditions.checkNotNull(attr, "attr must not be null");
1400 final IAudioService service = getService();
1401 try {
1402 return service.getMaxVolumeIndexForAttributes(attr);
1403 } catch (RemoteException e) {
1404 throw e.rethrowFromSystemServer();
1405 }
1406 }
1407
1408 /**
1409 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1410 *
1411 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1412 * @return The minimum valid volume index for the {@link AudioAttributes}.
1413 * @see #getVolumeIndexForAttributes(AudioAttributes)
1414 * @hide
1415 */
1416 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001417 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001418 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1419 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1420 Preconditions.checkNotNull(attr, "attr must not be null");
1421 final IAudioService service = getService();
1422 try {
1423 return service.getMinVolumeIndexForAttributes(attr);
1424 } catch (RemoteException e) {
1425 throw e.rethrowFromSystemServer();
1426 }
1427 }
1428
1429 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001430 * Set the system usages to be supported on this device.
1431 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1432 * @hide
1433 */
1434 @SystemApi
1435 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1436 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1437 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1438 final IAudioService service = getService();
1439 try {
1440 service.setSupportedSystemUsages(systemUsages);
1441 } catch (RemoteException e) {
1442 throw e.rethrowFromSystemServer();
1443 }
1444 }
1445
1446 /**
1447 * Get the system usages supported on this device.
1448 * @return array of supported system usages {@link AttributeSystemUsage}
1449 * @hide
1450 */
1451 @SystemApi
1452 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1453 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1454 final IAudioService service = getService();
1455 try {
1456 return service.getSupportedSystemUsages();
1457 } catch (RemoteException e) {
1458 throw e.rethrowFromSystemServer();
1459 }
1460 }
1461
1462 /**
RoboErik4197cb62015-01-21 15:45:32 -08001463 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001465 * Do not use. This method has been deprecated and is now a no-op.
1466 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 *
1468 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001469 * @param state The required solo state: true for solo ON, false for solo
1470 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001471 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001472 * @deprecated Do not use. If you need exclusive audio playback use
1473 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 */
RoboErik4197cb62015-01-21 15:45:32 -08001475 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001477 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 }
1479
1480 /**
1481 * Mute or unmute an audio stream.
1482 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001483 * This method should only be used by applications that replace the
1484 * platform-wide management of audio settings or the main telephony
1485 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001487 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001488 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001489 * <p>
1490 * This method was deprecated in API level 22. Prior to API level 22 this
1491 * method had significantly different behavior and should be used carefully.
1492 * The following applies only to pre-22 platforms:
1493 * <ul>
1494 * <li>The mute command is protected against client process death: if a
1495 * process with an active mute request on a stream dies, this stream will be
1496 * unmuted automatically.</li>
1497 * <li>The mute requests for a given stream are cumulative: the AudioManager
1498 * can receive several mute requests from one or more clients and the stream
1499 * will be unmuted only when the same number of unmute requests are
1500 * received.</li>
1501 * <li>For a better user experience, applications MUST unmute a muted stream
1502 * in onPause() and mute is again in onResume() if appropriate.</li>
1503 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 *
1505 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001506 * @param state The required mute state: true for mute ON, false for mute
1507 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001508 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001509 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1510 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 */
RoboErik4197cb62015-01-21 15:45:32 -08001512 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001514 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1515 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1516 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1517 adjustSuggestedStreamVolume(direction, streamType, 0);
1518 } else {
1519 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 }
1521 }
1522
1523 /**
RoboErik4197cb62015-01-21 15:45:32 -08001524 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001525 *
RoboErik4197cb62015-01-21 15:45:32 -08001526 * @param streamType The stream to get mute state for.
1527 * @return The mute state for the given stream.
1528 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001529 */
1530 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001531 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001532 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001533 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001534 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001535 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001536 }
1537 }
1538
1539 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001540 * get master mute state.
1541 *
1542 * @hide
1543 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001544 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001545 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001546 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001547 try {
1548 return service.isMasterMute();
1549 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001550 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001551 }
1552 }
1553
1554 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001555 * forces the stream controlled by hard volume keys
1556 * specifying streamType == -1 releases control to the
1557 * logic.
1558 *
1559 * @hide
1560 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001561 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001562 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001563 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001564 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001565 try {
1566 service.forceVolumeControlStream(streamType, mICallBack);
1567 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001568 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001569 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001570 }
1571
1572 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 * Returns whether a particular type should vibrate according to user
1574 * settings and the current ringer mode.
1575 * <p>
1576 * This shouldn't be needed by most clients that use notifications to
1577 * vibrate. The notification manager will not vibrate if the policy doesn't
1578 * allow it, so the client should always set a vibrate pattern and let the
1579 * notification manager control whether or not to actually vibrate.
1580 *
1581 * @param vibrateType The type of vibrate. One of
1582 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1583 * {@link #VIBRATE_TYPE_RINGER}.
1584 * @return Whether the type should vibrate at the instant this method is
1585 * called.
1586 * @see #setVibrateSetting(int, int)
1587 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001588 * @deprecated Applications should maintain their own vibrate policy based on
1589 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 */
1591 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001592 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 try {
1594 return service.shouldVibrate(vibrateType);
1595 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001596 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 }
1598 }
1599
1600 /**
1601 * Returns whether the user's vibrate setting for a vibrate type.
1602 * <p>
1603 * This shouldn't be needed by most clients that want to vibrate, instead
1604 * see {@link #shouldVibrate(int)}.
1605 *
1606 * @param vibrateType The type of vibrate. One of
1607 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1608 * {@link #VIBRATE_TYPE_RINGER}.
1609 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1610 * {@link #VIBRATE_SETTING_OFF}, or
1611 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1612 * @see #setVibrateSetting(int, int)
1613 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001614 * @deprecated Applications should maintain their own vibrate policy based on
1615 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 */
1617 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001618 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 try {
1620 return service.getVibrateSetting(vibrateType);
1621 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001622 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 }
1624 }
1625
1626 /**
1627 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001628 * <p>
1629 * This method should only be used by applications that replace the platform-wide
1630 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 *
1632 * @param vibrateType The type of vibrate. One of
1633 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1634 * {@link #VIBRATE_TYPE_RINGER}.
1635 * @param vibrateSetting The vibrate setting, one of
1636 * {@link #VIBRATE_SETTING_ON},
1637 * {@link #VIBRATE_SETTING_OFF}, or
1638 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1639 * @see #getVibrateSetting(int)
1640 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001641 * @deprecated Applications should maintain their own vibrate policy based on
1642 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 */
1644 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001645 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 try {
1647 service.setVibrateSetting(vibrateType, vibrateSetting);
1648 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001649 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 }
1651 }
1652
1653 /**
1654 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001655 * <p>
1656 * This method should only be used by applications that replace the platform-wide
1657 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 *
1659 * @param on set <var>true</var> to turn on speakerphone;
1660 * <var>false</var> to turn it off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001661 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or
1662 * {@link AudioManager#clearCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001664 @Deprecated public void setSpeakerphoneOn(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001665 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001666 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001667 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001668 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001669 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672
1673 /**
1674 * Checks whether the speakerphone is on or off.
1675 *
1676 * @return true if speakerphone is on, false if it's off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001677 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001679 @Deprecated public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001680 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001681 try {
1682 return service.isSpeakerphoneOn();
1683 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001684 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001685 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
1687
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001688 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001689 * 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 -07001690 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001691 *
1692 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1693 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001694 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001695 * <ul>
1696 * <li> for each track independently, see
1697 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1698 * <li> application-wide at runtime, with this method </li>
1699 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1700 * manifest. </li>
1701 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001702 * The most restrictive policy is always applied.
1703 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001704 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001705 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001706 *
1707 * @param capturePolicy one of
1708 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1709 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1710 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001711 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001712 */
1713 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001714 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001715 final IAudioService service = getService();
1716 try {
1717 int result = service.setAllowedCapturePolicy(capturePolicy);
1718 if (result != AudioSystem.AUDIO_STATUS_OK) {
1719 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1720 return;
1721 }
1722 } catch (RemoteException e) {
1723 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001724 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001725 }
1726
Kevin Rocard019f60d2019-04-09 16:25:26 -07001727 /**
1728 * Return the capture policy.
1729 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1730 * the default if it was not called.
1731 */
1732 @AudioAttributes.CapturePolicy
1733 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001734 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1735 try {
1736 result = getService().getAllowedCapturePolicy();
1737 } catch (RemoteException e) {
1738 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1739 }
1740 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001741 }
1742
Eric Laurent3def1ee2010-03-17 23:26:26 -07001743 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001744 // Audio Product Strategy routing
1745
1746 /**
1747 * @hide
1748 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1749 * this audio strategy. Note that the device may not be available at the time the preferred
1750 * device is set, but it will be used once made available.
1751 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1752 * this preference for this strategy.</p>
1753 * @param strategy the audio strategy whose routing will be affected
1754 * @param device the audio device to route to when available
1755 * @return true if the operation was successful, false otherwise
1756 */
1757 @SystemApi
1758 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1759 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001760 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001761 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001762 }
1763
1764 /**
1765 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001766 * Removes the preferred audio device(s) previously set with
1767 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1768 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001769 * @param strategy the audio strategy whose routing will be affected
1770 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1771 * device set for example)
1772 */
1773 @SystemApi
1774 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1775 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1776 Objects.requireNonNull(strategy);
1777 try {
1778 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001779 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001780 return status == AudioSystem.SUCCESS;
1781 } catch (RemoteException e) {
1782 throw e.rethrowFromSystemServer();
1783 }
1784 }
1785
1786 /**
1787 * @hide
1788 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001789 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1790 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1791 * @param strategy the strategy to query
1792 * @return the preferred device for that strategy, if multiple devices are set as preferred
1793 * devices, the first one in the list will be returned. Null will be returned if none was
1794 * ever set or if the strategy is invalid
1795 */
1796 @SystemApi
1797 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1798 @Nullable
1799 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1800 @NonNull AudioProductStrategy strategy) {
1801 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1802 return devices.isEmpty() ? null : devices.get(0);
1803 }
1804
1805 /**
1806 * @hide
1807 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1808 * this audio strategy. Note that the devices may not be available at the time the preferred
1809 * devices is set, but it will be used once made available.
1810 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1811 * this preference for this strategy.</p>
1812 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1813 * devices used simultaneously to output the same audio signal.
1814 * @param strategy the audio strategy whose routing will be affected
1815 * @param devices a non-empty list of the audio devices to route to when available
1816 * @return true if the operation was successful, false otherwise
1817 */
1818 @SystemApi
1819 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1820 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1821 @NonNull List<AudioDeviceAttributes> devices) {
1822 Objects.requireNonNull(strategy);
1823 Objects.requireNonNull(devices);
1824 if (devices.isEmpty()) {
1825 throw new IllegalArgumentException(
1826 "Tried to set preferred devices for strategy with a empty list");
1827 }
1828 for (AudioDeviceAttributes device : devices) {
1829 Objects.requireNonNull(device);
1830 }
1831 try {
1832 final int status =
1833 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1834 return status == AudioSystem.SUCCESS;
1835 } catch (RemoteException e) {
1836 throw e.rethrowFromSystemServer();
1837 }
1838 }
1839
1840 /**
1841 * @hide
1842 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001843 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001844 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001845 * @param strategy the strategy to query
Paul Wang8ee29602022-12-22 03:40:19 +00001846 * @return list of the preferred devices for that strategy
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001847 */
1848 @SystemApi
1849 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001850 @NonNull
1851 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001852 @NonNull AudioProductStrategy strategy) {
1853 Objects.requireNonNull(strategy);
1854 try {
jiabinf40141d2020-08-07 17:27:48 -07001855 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001856 } catch (RemoteException e) {
1857 throw e.rethrowFromSystemServer();
1858 }
1859 }
1860
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001861 /**
1862 * @hide
Paul Wangee4774a2022-08-23 09:41:03 +00001863 * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by
1864 * this audio strategy.
1865 * <p>Use
1866 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
1867 * to cancel setting this preference for this strategy.</p>
1868 * @param strategy the audio strategy whose routing will be affected
1869 * @param device the audio device to not route to when available
1870 * @return true if the operation was successful, false otherwise
1871 */
1872 @SystemApi
1873 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1874 public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
1875 @NonNull AudioDeviceAttributes device) {
1876 Objects.requireNonNull(strategy);
1877 Objects.requireNonNull(device);
1878 try {
1879 final int status =
1880 getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device);
1881 return status == AudioSystem.SUCCESS;
1882 } catch (RemoteException e) {
1883 throw e.rethrowFromSystemServer();
1884 }
1885 }
1886
1887 /**
1888 * @hide
1889 * Removes the audio device(s) from the non-default device list previously set with
1890 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
1891 * @param strategy the audio strategy whose routing will be affected
1892 * @param device the audio device to remove from the non-default device list
1893 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1894 * device set for example)
1895 */
1896 @SystemApi
1897 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1898 public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
1899 @NonNull AudioDeviceAttributes device) {
1900 Objects.requireNonNull(strategy);
1901 Objects.requireNonNull(device);
1902 try {
1903 final int status =
1904 getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device);
1905 return status == AudioSystem.SUCCESS;
1906 } catch (RemoteException e) {
1907 throw e.rethrowFromSystemServer();
1908 }
1909 }
1910
1911 /**
1912 * @hide
1913 * Gets the audio device(s) from the non-default device list previously set with
1914 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
1915 * @param strategy the audio strategy to query
1916 * @return list of non-default devices for the strategy
1917 */
1918 @SystemApi
1919 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1920 @NonNull
1921 public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
1922 @NonNull AudioProductStrategy strategy) {
1923 Objects.requireNonNull(strategy);
1924 try {
1925 return getService().getNonDefaultDevicesForStrategy(strategy.getId());
1926 } catch (RemoteException e) {
1927 throw e.rethrowFromSystemServer();
1928 }
1929 }
1930
1931 /**
1932 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001933 * Interface to be notified of changes in the preferred audio device set for a given audio
1934 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001935 * <p>Note that this listener will only be invoked whenever
1936 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001937 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001938 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1939 * preferred device. It will not be invoked directly after registration with
1940 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1941 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001942 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001943 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1944 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001945 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001946 */
1947 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001948 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001949 public interface OnPreferredDeviceForStrategyChangedListener {
1950 /**
1951 * Called on the listener to indicate that the preferred audio device for the given
1952 * strategy has changed.
1953 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1954 * @param device <code>null</code> if the preferred device was removed, or the newly set
1955 * preferred audio device
1956 */
1957 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001958 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001959 }
1960
1961 /**
1962 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001963 * Interface to be notified of changes in the preferred audio devices set for a given audio
1964 * strategy.
1965 * <p>Note that this listener will only be invoked whenever
Paul Wangee4774a2022-08-23 09:41:03 +00001966 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
1967 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
1968 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
1969 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
1970 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
jiabinf40141d2020-08-07 17:27:48 -07001971 * preferred device(s). It will not be invoked directly after registration with
1972 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1973 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1974 * to indicate which strategies had preferred devices at the time of registration.</p>
1975 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1976 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1977 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001978 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1979 */
1980 @SystemApi
1981 public interface OnPreferredDevicesForStrategyChangedListener {
1982 /**
1983 * Called on the listener to indicate that the preferred audio devices for the given
1984 * strategy has changed.
1985 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1986 * @param devices a list of newly set preferred audio devices
1987 */
1988 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1989 @NonNull List<AudioDeviceAttributes> devices);
1990 }
1991
1992 /**
1993 * @hide
1994 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1995 * @param executor
1996 * @param listener
1997 * @throws SecurityException if the caller doesn't hold the required permission
1998 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1999 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2000 */
2001 @SystemApi
2002 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2003 @Deprecated
2004 public void addOnPreferredDeviceForStrategyChangedListener(
2005 @NonNull @CallbackExecutor Executor executor,
2006 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
2007 throws SecurityException {
2008 // No-op, the method is deprecated.
2009 }
2010
2011 /**
2012 * @hide
2013 * Removes a previously added listener of changes to the strategy-preferred audio device.
2014 * @param listener
2015 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
2016 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2017 */
2018 @SystemApi
2019 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2020 @Deprecated
2021 public void removeOnPreferredDeviceForStrategyChangedListener(
2022 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
2023 // No-op, the method is deprecated.
2024 }
2025
2026 /**
2027 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002028 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2029 * @param executor
2030 * @param listener
2031 * @throws SecurityException if the caller doesn't hold the required permission
2032 */
2033 @SystemApi
2034 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002035 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002036 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07002037 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002038 throws SecurityException {
2039 Objects.requireNonNull(executor);
2040 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002041 mPrefDevListenerMgr.addListener(
2042 executor, listener, "addOnPreferredDevicesForStrategyChangedListener",
2043 () -> new StrategyPreferredDevicesDispatcherStub());
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002044 }
2045
2046 /**
2047 * @hide
2048 * Removes a previously added listener of changes to the strategy-preferred audio device.
2049 * @param listener
2050 */
2051 @SystemApi
2052 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002053 public void removeOnPreferredDevicesForStrategyChangedListener(
2054 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002055 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002056 mPrefDevListenerMgr.removeListener(
2057 listener, "removeOnPreferredDevicesForStrategyChangedListener");
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002058 }
2059
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002060 /**
Paul Wangee4774a2022-08-23 09:41:03 +00002061 * @hide
2062 * Interface to be notified of changes in the non-default audio devices set for a given audio
2063 * strategy.
2064 * <p>Note that this listener will only be invoked whenever
2065 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2066 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2067 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2068 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2069 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2070 * non-default device(s). It will not be invoked directly after registration with
2071 * {@link #addOnNonDefaultDevicesForStrategyChangedListener(
2072 * Executor, OnNonDefaultDevicesForStrategyChangedListener)}
2073 * to indicate which strategies had preferred devices at the time of registration.</p>
2074 * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2075 * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2076 */
2077 @SystemApi
2078 public interface OnNonDefaultDevicesForStrategyChangedListener {
2079 /**
2080 * Called on the listener to indicate that the non-default audio devices for the given
2081 * strategy has changed.
2082 * @param strategy the {@link AudioProductStrategy} whose non-default device changed
2083 * @param devices a list of newly set non-default audio devices
2084 */
2085 void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2086 @NonNull List<AudioDeviceAttributes> devices);
2087 }
2088
2089 /**
2090 * @hide
2091 * Adds a listener for being notified of changes to the non-default audio devices for
2092 * strategies.
2093 * @param executor
2094 * @param listener
2095 * @throws SecurityException if the caller doesn't hold the required permission
2096 */
2097 @SystemApi
2098 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2099 public void addOnNonDefaultDevicesForStrategyChangedListener(
2100 @NonNull @CallbackExecutor Executor executor,
2101 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
2102 throws SecurityException {
2103 Objects.requireNonNull(executor);
2104 Objects.requireNonNull(listener);
2105
2106 mNonDefDevListenerMgr.addListener(
2107 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener",
2108 () -> new StrategyNonDefaultDevicesDispatcherStub());
2109 }
2110
2111 /**
2112 * @hide
2113 * Removes a previously added listener of changes to the non-default audio device for
2114 * strategies.
2115 * @param listener
2116 */
2117 @SystemApi
2118 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2119 public void removeOnNonDefaultDevicesForStrategyChangedListener(
2120 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
2121 Objects.requireNonNull(listener);
2122 mNonDefDevListenerMgr.removeListener(
2123 listener, "removeOnNonDefaultDevicesForStrategyChangedListener");
2124 }
2125
2126 /**
Paul Wang8ee29602022-12-22 03:40:19 +00002127 * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the
2128 * StrategyPreferredDevicesDispatcherStub
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002129 */
Paul Wang8ee29602022-12-22 03:40:19 +00002130 private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener>
2131 mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002132
Paul Wangee4774a2022-08-23 09:41:03 +00002133 /**
2134 * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the
2135 * StrategyNonDefaultDevicesDispatcherStub
2136 */
2137 private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener>
2138 mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager();
2139
jiabinf40141d2020-08-07 17:27:48 -07002140 private final class StrategyPreferredDevicesDispatcherStub
Paul Wang8ee29602022-12-22 03:40:19 +00002141 extends IStrategyPreferredDevicesDispatcher.Stub
2142 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002143
2144 @Override
jiabinf40141d2020-08-07 17:27:48 -07002145 public void dispatchPrefDevicesChanged(int strategyId,
2146 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002147 final AudioProductStrategy strategy =
2148 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
Paul Wang8ee29602022-12-22 03:40:19 +00002149
2150 mPrefDevListenerMgr.callListeners(
2151 (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices));
2152 }
2153
2154 @Override
2155 public void register(boolean register) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002156 try {
Paul Wang8ee29602022-12-22 03:40:19 +00002157 if (register) {
2158 getService().registerStrategyPreferredDevicesDispatcher(this);
2159 } else {
2160 getService().unregisterStrategyPreferredDevicesDispatcher(this);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002161 }
Paul Wang8ee29602022-12-22 03:40:19 +00002162 } catch (RemoteException e) {
2163 e.rethrowFromSystemServer();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002164 }
2165 }
2166 }
2167
Paul Wangee4774a2022-08-23 09:41:03 +00002168 private final class StrategyNonDefaultDevicesDispatcherStub
2169 extends IStrategyNonDefaultDevicesDispatcher.Stub
2170 implements CallbackUtil.DispatcherStub {
2171
2172 @Override
2173 public void dispatchNonDefDevicesChanged(int strategyId,
2174 @NonNull List<AudioDeviceAttributes> devices) {
2175 final AudioProductStrategy strategy =
2176 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2177
2178 mNonDefDevListenerMgr.callListeners(
2179 (listener) -> listener.onNonDefaultDevicesForStrategyChanged(
2180 strategy, devices));
2181 }
2182
2183 @Override
2184 public void register(boolean register) {
2185 try {
2186 if (register) {
2187 getService().registerStrategyNonDefaultDevicesDispatcher(this);
2188 } else {
2189 getService().unregisterStrategyNonDefaultDevicesDispatcher(this);
2190 }
2191 } catch (RemoteException e) {
2192 e.rethrowFromSystemServer();
2193 }
2194 }
2195 }
2196
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002197 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002198 // Audio Capture Preset routing
2199
2200 /**
2201 * @hide
2202 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2203 * this capture preset. Note that the device may not be available at the time the preferred
2204 * device is set, but it will be used once made available.
2205 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2206 * for this capture preset.</p>
2207 * @param capturePreset the audio capture preset whose routing will be affected
2208 * @param device the audio device to route to when available
2209 * @return true if the operation was successful, false otherwise
2210 */
2211 @SystemApi
2212 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002213 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002214 @NonNull AudioDeviceAttributes device) {
2215 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2216 }
2217
2218 /**
2219 * @hide
2220 * Remove all the preferred audio devices previously set
2221 * @param capturePreset the audio capture preset whose routing will be affected
2222 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2223 * device set for example)
2224 */
2225 @SystemApi
2226 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002227 public boolean clearPreferredDevicesForCapturePreset(
2228 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002229 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2230 return false;
2231 }
2232 try {
2233 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2234 return status == AudioSystem.SUCCESS;
2235 } catch (RemoteException e) {
2236 throw e.rethrowFromSystemServer();
2237 }
2238 }
2239
2240 /**
2241 * @hide
2242 * Return the preferred devices for an audio capture preset, previously set with
2243 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2244 * @param capturePreset the capture preset to query
2245 * @return a list that contains preferred devices for that capture preset.
2246 */
2247 @NonNull
2248 @SystemApi
2249 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002250 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2251 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002252 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2253 return new ArrayList<AudioDeviceAttributes>();
2254 }
2255 try {
2256 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2257 } catch (RemoteException e) {
2258 throw e.rethrowFromSystemServer();
2259 }
2260 }
2261
2262 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002263 @MediaRecorder.SystemSource int capturePreset,
2264 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002265 Objects.requireNonNull(devices);
2266 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2267 return false;
2268 }
2269 if (devices.size() != 1) {
2270 throw new IllegalArgumentException(
2271 "Only support setting one preferred devices for capture preset");
2272 }
2273 for (AudioDeviceAttributes device : devices) {
2274 Objects.requireNonNull(device);
2275 }
2276 try {
2277 final int status =
2278 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2279 return status == AudioSystem.SUCCESS;
2280 } catch (RemoteException e) {
2281 throw e.rethrowFromSystemServer();
2282 }
2283 }
2284
2285 /**
2286 * @hide
2287 * Interface to be notified of changes in the preferred audio devices set for a given capture
2288 * preset.
2289 * <p>Note that this listener will only be invoked whenever
2290 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2291 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2292 * preferred device. It will not be invoked directly after registration with
2293 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2294 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2295 * to indicate which strategies had preferred devices at the time of registration.</p>
2296 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2297 * @see #clearPreferredDevicesForCapturePreset(int)
2298 * @see #getPreferredDevicesForCapturePreset(int)
2299 */
2300 @SystemApi
2301 public interface OnPreferredDevicesForCapturePresetChangedListener {
2302 /**
2303 * Called on the listener to indicate that the preferred audio devices for the given
2304 * capture preset has changed.
2305 * @param capturePreset the capture preset whose preferred device changed
2306 * @param devices a list of newly set preferred audio devices
2307 */
2308 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002309 @MediaRecorder.SystemSource int capturePreset,
2310 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002311 }
2312
2313 /**
2314 * @hide
2315 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2316 * @param executor
2317 * @param listener
2318 * @throws SecurityException if the caller doesn't hold the required permission
2319 */
2320 @SystemApi
2321 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2322 public void addOnPreferredDevicesForCapturePresetChangedListener(
2323 @NonNull @CallbackExecutor Executor executor,
2324 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2325 throws SecurityException {
2326 Objects.requireNonNull(executor);
2327 Objects.requireNonNull(listener);
2328 int status = addOnDevRoleForCapturePresetChangedListener(
2329 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2330 if (status == AudioSystem.ERROR) {
2331 // This must not happen
2332 throw new RuntimeException("Unknown error happened");
2333 }
2334 if (status == AudioSystem.BAD_VALUE) {
2335 throw new IllegalArgumentException(
2336 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2337 + "on a previously registered listener");
2338 }
2339 }
2340
2341 /**
2342 * @hide
2343 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2344 * @param listener
2345 */
2346 @SystemApi
2347 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2348 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2349 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2350 Objects.requireNonNull(listener);
2351 int status = removeOnDevRoleForCapturePresetChangedListener(
2352 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2353 if (status == AudioSystem.ERROR) {
2354 // This must not happen
2355 throw new RuntimeException("Unknown error happened");
2356 }
2357 if (status == AudioSystem.BAD_VALUE) {
2358 throw new IllegalArgumentException(
2359 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2360 + "on an unregistered listener");
2361 }
2362 }
2363
2364 private <T> int addOnDevRoleForCapturePresetChangedListener(
2365 @NonNull @CallbackExecutor Executor executor,
2366 @NonNull T listener, int deviceRole) {
2367 Objects.requireNonNull(executor);
2368 Objects.requireNonNull(listener);
2369 DevRoleListeners<T> devRoleListeners =
2370 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2371 if (devRoleListeners == null) {
2372 return AudioSystem.ERROR;
2373 }
2374 synchronized (devRoleListeners.mDevRoleListenersLock) {
2375 if (devRoleListeners.hasDevRoleListener(listener)) {
2376 return AudioSystem.BAD_VALUE;
2377 }
2378 // lazy initialization of the list of device role listener
2379 if (devRoleListeners.mListenerInfos == null) {
2380 devRoleListeners.mListenerInfos = new ArrayList<>();
2381 }
2382 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2383 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2384 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2385 // register binder for callbacks
2386 synchronized (mDevRoleForCapturePresetListenersLock) {
2387 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2388 mDeviceRoleListenersStatus |= (1 << deviceRole);
2389 if (deviceRoleListenerStatus != 0) {
2390 // There are already device role changed listeners active.
2391 return AudioSystem.SUCCESS;
2392 }
2393 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2394 mDevicesRoleForCapturePresetDispatcherStub =
2395 new CapturePresetDevicesRoleDispatcherStub();
2396 }
2397 try {
2398 getService().registerCapturePresetDevicesRoleDispatcher(
2399 mDevicesRoleForCapturePresetDispatcherStub);
2400 } catch (RemoteException e) {
2401 throw e.rethrowFromSystemServer();
2402 }
2403 }
2404 }
2405 }
2406 return AudioSystem.SUCCESS;
2407 }
2408
2409 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2410 @NonNull T listener, int deviceRole) {
2411 Objects.requireNonNull(listener);
2412 DevRoleListeners<T> devRoleListeners =
2413 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2414 if (devRoleListeners == null) {
2415 return AudioSystem.ERROR;
2416 }
2417 synchronized (devRoleListeners.mDevRoleListenersLock) {
2418 if (!devRoleListeners.removeDevRoleListener(listener)) {
2419 return AudioSystem.BAD_VALUE;
2420 }
2421 if (devRoleListeners.mListenerInfos.size() == 0) {
2422 // unregister binder for callbacks
2423 synchronized (mDevRoleForCapturePresetListenersLock) {
2424 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2425 if (mDeviceRoleListenersStatus != 0) {
2426 // There are some other device role changed listeners active.
2427 return AudioSystem.SUCCESS;
2428 }
2429 try {
2430 getService().unregisterCapturePresetDevicesRoleDispatcher(
2431 mDevicesRoleForCapturePresetDispatcherStub);
2432 } catch (RemoteException e) {
2433 throw e.rethrowFromSystemServer();
2434 }
2435 }
2436 }
2437 }
2438 return AudioSystem.SUCCESS;
2439 }
2440
Cole Faust7da659b2022-10-15 21:33:29 -07002441 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of(
2442 AudioSystem.DEVICE_ROLE_PREFERRED,
2443 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
Jiabin Huangb55305f2020-09-03 17:54:16 +00002444
2445 private class DevRoleListenerInfo<T> {
2446 final @NonNull Executor mExecutor;
2447 final @NonNull T mListener;
2448 DevRoleListenerInfo(Executor executor, T listener) {
2449 mExecutor = executor;
2450 mListener = listener;
2451 }
2452 }
2453
2454 private class DevRoleListeners<T> {
2455 private final Object mDevRoleListenersLock = new Object();
2456 @GuardedBy("mDevRoleListenersLock")
2457 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2458
2459 @GuardedBy("mDevRoleListenersLock")
2460 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2461 if (mListenerInfos == null) {
2462 return null;
2463 }
2464 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2465 if (listenerInfo.mListener == listener) {
2466 return listenerInfo;
2467 }
2468 }
2469 return null;
2470 }
2471
2472 @GuardedBy("mDevRoleListenersLock")
2473 private boolean hasDevRoleListener(T listener) {
2474 return getDevRoleListenerInfo(listener) != null;
2475 }
2476
2477 @GuardedBy("mDevRoleListenersLock")
2478 private boolean removeDevRoleListener(T listener) {
2479 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2480 if (infoToRemove != null) {
2481 mListenerInfos.remove(infoToRemove);
2482 return true;
2483 }
2484 return false;
2485 }
2486 }
2487
2488 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2489 /**
2490 * Record if there is a listener added for device role change. If there is a listener added for
2491 * a specified device role change, the bit at position `1 << device_role` is set.
2492 */
2493 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2494 private int mDeviceRoleListenersStatus = 0;
2495 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2496 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2497
2498 private final class CapturePresetDevicesRoleDispatcherStub
2499 extends ICapturePresetDevicesRoleDispatcher.Stub {
2500
2501 @Override
2502 public void dispatchDevicesRoleChanged(
2503 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2504 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2505 if (listenersObj == null) {
2506 return;
2507 }
2508 switch (role) {
2509 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2510 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2511 listeners =
2512 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2513 listenersObj;
2514 final ArrayList<DevRoleListenerInfo<
2515 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2516 synchronized (listeners.mDevRoleListenersLock) {
2517 if (listeners.mListenerInfos.isEmpty()) {
2518 return;
2519 }
2520 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2521 OnPreferredDevicesForCapturePresetChangedListener>>)
2522 listeners.mListenerInfos.clone();
2523 }
2524 final long ident = Binder.clearCallingIdentity();
2525 try {
2526 for (DevRoleListenerInfo<
2527 OnPreferredDevicesForCapturePresetChangedListener> info :
2528 prefDevListeners) {
2529 info.mExecutor.execute(() ->
2530 info.mListener.onPreferredDevicesForCapturePresetChanged(
2531 capturePreset, devices));
2532 }
2533 } finally {
2534 Binder.restoreCallingIdentity(ident);
2535 }
2536 } break;
2537 default:
2538 break;
2539 }
2540 }
2541 }
2542
2543 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002544 // Direct playback query
2545
2546 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2547 direct playback not supported. */
2548 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2549 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2550 direct offload playback supported. Compressed offload is a variant of direct playback.
2551 It is the feature that allows audio processing tasks to be done on the Android device but
2552 not on the application processor, instead, it is handled by dedicated hardware such as audio
2553 DSPs. That will allow the application processor to be idle as much as possible, which is
2554 good for power saving. Compressed offload playback supports
2555 {@link AudioTrack.StreamEventCallback} for event notifications. */
2556 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2557 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2558 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2559 direct offload playback supported with gapless transitions. Compressed offload is a variant
2560 of direct playback. It is the feature that allows audio processing tasks to be done on the
2561 Android device but not on the application processor, instead, it is handled by dedicated
2562 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2563 possible, which is good for power saving. Compressed offload playback supports
2564 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2565 indicates the ability to play consecutive audio tracks without an audio silence in
2566 between. */
2567 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2568 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2569 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2570 direct playback supported. This value covers direct playback that is bitstream pass-through
2571 such as compressed pass-through. */
2572 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2573 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2574
2575 /** @hide */
2576 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2577 DIRECT_PLAYBACK_NOT_SUPPORTED,
2578 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2579 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2580 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2581 )
2582 @Retention(RetentionPolicy.SOURCE)
2583 public @interface AudioDirectPlaybackMode {}
2584
2585 /**
2586 * Returns a bitfield representing the different forms of direct playback currently available
2587 * for a given audio format.
2588 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2589 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2590 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2591 * passthrough.
2592 * <p>Checking for direct support can help the app select the representation of audio content
2593 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2594 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2595 * streams, if needed.
2596 * @param format the audio format (codec, sample rate, channels) being checked.
2597 * @param attributes the {@link AudioAttributes} to be used for playback
2598 * @return the direct playback mode available with given format and attributes. The returned
2599 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2600 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2601 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2602 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2603 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2604 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2605 */
2606 @AudioDirectPlaybackMode
2607 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2608 @NonNull AudioAttributes attributes) {
2609 Objects.requireNonNull(format);
2610 Objects.requireNonNull(attributes);
2611 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2612 }
2613
2614 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002615 // Offload query
2616 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002617 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002618 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2619 * is not competing with other software resources. In general, it is supported by dedicated
2620 * hardware, such as audio DSPs.
2621 * <p>Note that this query only provides information about the support of an audio format,
2622 * it does not indicate whether the resources necessary for the offloaded playback are
2623 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002624 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002625 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002626 * @return true if the given audio format can be offloaded.
2627 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002628 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2629 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002630 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002631 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002632 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002633 if (attributes == null) {
2634 throw new NullPointerException("Illegal null AudioAttributes");
2635 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002636 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2637 }
2638
2639 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2640 offload playback not supported */
2641 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2642 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2643 offload playback supported */
2644 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2645 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2646 offload playback supported with gapless transitions */
2647 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2648 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2649
2650 /** @hide */
2651 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2652 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2653 PLAYBACK_OFFLOAD_SUPPORTED,
2654 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2655 )
2656 @Retention(RetentionPolicy.SOURCE)
2657 public @interface AudioOffloadMode {}
2658
2659 /**
2660 * Returns whether offloaded playback of an audio format is supported on the device or not and
2661 * when supported whether gapless transitions are possible or not.
2662 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2663 * is not competing with other software resources. In general, it is supported by dedicated
2664 * hardware, such as audio DSPs.
2665 * <p>Note that this query only provides information about the support of an audio format,
2666 * it does not indicate whether the resources necessary for the offloaded playback are
2667 * available at that instant.
2668 * @param format the audio format (codec, sample rate, channels) being checked.
2669 * @param attributes the {@link AudioAttributes} to be used for playback
2670 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2671 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2672 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2673 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002674 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002675 */
jiabine22f6aa2021-12-10 01:09:02 +00002676 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002677 @AudioOffloadMode
2678 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2679 @NonNull AudioAttributes attributes) {
2680 if (format == null) {
2681 throw new NullPointerException("Illegal null AudioFormat");
2682 }
2683 if (attributes == null) {
2684 throw new NullPointerException("Illegal null AudioAttributes");
2685 }
2686 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002687 }
2688
2689 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002690 // Immersive audio
2691
2692 /**
2693 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002694 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002695 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2696 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002697 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002698 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002699 return new Spatializer(this);
2700 }
2701
2702 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002703 // Bluetooth SCO control
2704 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002705 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002706 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002707 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2708 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2709 *
2710 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002711 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002712 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002713 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002714 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2715 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2716 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002717
2718 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002719 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002720 * connection state has been updated.
2721 * <p>This intent has two extras:
2722 * <ul>
2723 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2724 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2725 * </ul>
2726 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2727 * <ul>
2728 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2729 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2730 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2731 * </ul>
2732 * @see #startBluetoothSco()
2733 */
2734 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2735 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2736 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2737
Eric Laurent3def1ee2010-03-17 23:26:26 -07002738 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002739 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2740 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002741 */
2742 public static final String EXTRA_SCO_AUDIO_STATE =
2743 "android.media.extra.SCO_AUDIO_STATE";
2744
2745 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002746 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2747 * bluetooth SCO connection state.
2748 */
2749 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2750 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2751
2752 /**
2753 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2754 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002755 */
2756 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2757 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002758 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2759 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002760 */
2761 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2762 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002763 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2764 * indicating that the SCO audio channel is being established
2765 */
2766 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2767 /**
2768 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002769 * there was an error trying to obtain the state
2770 */
2771 public static final int SCO_AUDIO_STATE_ERROR = -1;
2772
2773
2774 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002775 * Indicates if current platform supports use of SCO for off call use cases.
2776 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002777 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002778 * feature.
2779 * @return true if bluetooth SCO can be used for audio when not in call
2780 * false otherwise
2781 * @see #startBluetoothSco()
2782 */
2783 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002784 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002785 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2786 }
2787
2788 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002789 * Start bluetooth SCO audio connection.
2790 * <p>Requires Permission:
2791 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2792 * <p>This method can be used by applications wanting to send and received audio
2793 * to/from a bluetooth SCO headset while the phone is not in call.
2794 * <p>As the SCO connection establishment can take several seconds,
2795 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002796 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002797 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002798 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2799 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2800 * registration. If the state is already CONNECTED, no state change will be received via the
2801 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2802 * so that the connection stays active in case the current initiator stops the connection.
2803 * <p>Unless the connection is already active as described above, the state will always
2804 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2805 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2806 * <p>When finished with the SCO connection or if the establishment fails, the application must
2807 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002808 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2809 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002810 * <ul>
2811 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2812 * <li> the format must be mono </li>
2813 * <li> the sampling must be 16kHz or 8kHz </li>
2814 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002815 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002816 * <ul>
2817 * <li> the format must be mono </li>
2818 * <li> the sampling must be 8kHz </li>
2819 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002820 * <p>Note that the phone application always has the priority on the usage of the SCO
2821 * connection for telephony. If this method is called while the phone is in call
2822 * it will be ignored. Similarly, if a call is received or sent while an application
2823 * is using the SCO connection, the connection will be lost for the application and NOT
2824 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002825 * <p>NOTE: up to and including API version
2826 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2827 * voice call to the bluetooth headset.
2828 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2829 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002830 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002831 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurentf23f1b72022-02-18 10:57:54 +01002832 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002833 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01002834 @Deprecated public void startBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002835 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002836 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002837 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002838 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002839 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002840 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002841 }
2842 }
2843
2844 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002845 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002846 * Start bluetooth SCO audio connection in virtual call mode.
2847 * <p>Requires Permission:
2848 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2849 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2850 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2851 * virtual call mode.
2852 * Applications using voice input for search or commands should first try raw audio connection
2853 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2854 * failure.
2855 * @see #startBluetoothSco()
2856 * @see #stopBluetoothSco()
2857 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2858 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002859 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002860 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002861 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002862 try {
2863 service.startBluetoothScoVirtualCall(mICallBack);
2864 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002865 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002866 }
2867 }
2868
2869 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002870 * Stop bluetooth SCO audio connection.
2871 * <p>Requires Permission:
2872 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2873 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002874 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2875 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002876 * @see #startBluetoothSco()
Eric Laurentf23f1b72022-02-18 10:57:54 +01002877 * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002878 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002879 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurentf23f1b72022-02-18 10:57:54 +01002880 @Deprecated public void stopBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002881 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002882 try {
2883 service.stopBluetoothSco(mICallBack);
2884 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002885 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002886 }
2887 }
2888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002890 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002891 * <p>
2892 * This method should only be used by applications that replace the platform-wide
2893 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002894 *
Eric Laurenta553c252009-07-17 12:17:14 -07002895 * @param on set <var>true</var> to use bluetooth SCO for communications;
2896 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002897 */
2898 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002899 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002900 try {
2901 service.setBluetoothScoOn(on);
2902 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002903 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002905 }
2906
2907 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002908 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002909 *
Eric Laurenta553c252009-07-17 12:17:14 -07002910 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 * false if otherwise
Eric Laurentf23f1b72022-02-18 10:57:54 +01002912 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01002914 @Deprecated public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002915 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002916 try {
2917 return service.isBluetoothScoOn();
2918 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002919 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 }
2922
2923 /**
Santiago Seifert1d8f6172022-08-25 14:34:44 +00002924 * @deprecated Use {@link MediaRouter#selectRoute} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 */
Eric Laurenta553c252009-07-17 12:17:14 -07002926 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002927 }
2928
2929 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002930 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002931 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002932 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002933 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002934 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 */
2936 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002937 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002938 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2939 return true;
2940 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2941 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2942 return true;
2943 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2944 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002945 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002946 }
Eric Laurent9656df22016-04-20 16:42:28 -07002947 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 }
2949
2950 /**
2951 * Sets audio routing to the wired headset on or off.
2952 *
2953 * @param on set <var>true</var> to route audio to/from wired
2954 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002955 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956 */
Eric Laurenta553c252009-07-17 12:17:14 -07002957 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002958 }
2959
2960 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002961 * Checks whether a wired headset is connected or not.
2962 * <p>This is not a valid indication that audio playback is
2963 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002965 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002967 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 */
2969 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002970 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002971 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002972 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002973 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2974 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2975 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002976 return false;
2977 } else {
2978 return true;
2979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 }
2981
2982 /**
2983 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002984 * <p>
2985 * This method should only be used by applications that replace the platform-wide
2986 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987 *
2988 * @param on set <var>true</var> to mute the microphone;
2989 * <var>false</var> to turn mute off
2990 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002991 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002992 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002993 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002994 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002995 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002996 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002997 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002998 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 }
3000
3001 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003002 * @hide
3003 * Sets the microphone from switch mute on or off.
3004 * <p>
3005 * This method should only be used by InputManager to notify
3006 * Audio Subsystem about Microphone Mute switch state.
3007 *
3008 * @param on set <var>true</var> to mute the microphone;
3009 * <var>false</var> to turn mute off
3010 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003011 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003012 public void setMicrophoneMuteFromSwitch(boolean on) {
3013 final IAudioService service = getService();
3014 try {
3015 service.setMicrophoneMuteFromSwitch(on);
3016 } catch (RemoteException e) {
3017 throw e.rethrowFromSystemServer();
3018 }
3019 }
3020
3021 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003022 * Checks whether the microphone mute is on or off.
3023 *
3024 * @return true if microphone is muted, false if it's not
3025 */
3026 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003027 final IAudioService service = getService();
3028 try {
3029 return service.isMicrophoneMuted();
3030 } catch (RemoteException e) {
3031 throw e.rethrowFromSystemServer();
3032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 }
3034
3035 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08003036 * Broadcast Action: microphone muting state changed.
3037 *
3038 * You <em>cannot</em> receive this through components declared
3039 * in manifests, only by explicitly registering for it with
3040 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3041 * Context.registerReceiver()}.
3042 *
3043 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
3044 * microphone is muted.
3045 */
3046 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3047 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
3048 "android.media.action.MICROPHONE_MUTE_CHANGED";
3049
3050 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07003051 * Broadcast Action: speakerphone state changed.
3052 *
3053 * You <em>cannot</em> receive this through components declared
3054 * in manifests, only by explicitly registering for it with
3055 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3056 * Context.registerReceiver()}.
3057 *
3058 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
3059 * speakerphone functionality is enabled or not.
3060 */
3061 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3062 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
3063 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
3064
3065 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003066 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003067 * <p>
3068 * The audio mode encompasses audio routing AND the behavior of
3069 * the telephony layer. Therefore this method should only be used by applications that
3070 * replace the platform-wide management of audio settings or the main telephony application.
3071 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
3072 * application when it places a phone call, as it will cause signals from the radio layer
3073 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003075 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 * Informs the HAL about the current audio state so that
3077 * it can route the audio appropriately.
3078 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003079 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003080 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07003082 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003083 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003084 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085 }
3086 }
3087
3088 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01003089 * This change id controls use of audio modes for call audio redirection.
3090 * @hide
3091 */
3092 @ChangeId
3093 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
3094 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
3095
3096 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 * Returns the current audio mode.
3098 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003099 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003101 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003103 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003105 int mode = service.getMode();
3106 int sdk;
3107 try {
3108 sdk = getContext().getApplicationInfo().targetSdkVersion;
3109 } catch (NullPointerException e) {
3110 // some tests don't have a Context
3111 sdk = Build.VERSION.SDK_INT;
3112 }
3113 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3114 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01003115 } else if (mode == MODE_CALL_REDIRECT
3116 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3117 mode = MODE_IN_CALL;
3118 } else if (mode == MODE_COMMUNICATION_REDIRECT
3119 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3120 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003121 }
3122 return mode;
3123 } catch (RemoteException e) {
3124 throw e.rethrowFromSystemServer();
3125 }
3126 }
3127
3128 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003129 * Interface definition of a callback that is notified when the audio mode changes
3130 */
3131 public interface OnModeChangedListener {
3132 /**
3133 * Called on the listener to indicate that the audio mode has changed
3134 *
3135 * @param mode The current audio mode
3136 */
3137 void onModeChanged(@AudioMode int mode);
3138 }
3139
Nate Myren08635fe2021-04-20 12:04:39 -07003140 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003141 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003142 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003143 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3144 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003145
Nate Myren08635fe2021-04-20 12:04:39 -07003146
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003147 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3148 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003149
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003150 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003151 public void register(boolean register) {
3152 try {
3153 if (register) {
3154 getService().registerModeDispatcher(this);
3155 } else {
3156 getService().unregisterModeDispatcher(this);
3157 }
3158 } catch (RemoteException e) {
3159 e.rethrowFromSystemServer();
3160 }
3161 }
Nate Myren08635fe2021-04-20 12:04:39 -07003162
3163 @Override
3164 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003165 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003166 }
3167 }
3168
Nate Myren08635fe2021-04-20 12:04:39 -07003169 /**
3170 * Adds a listener to be notified of changes to the audio mode.
3171 * See {@link #getMode()}
3172 * @param executor
3173 * @param listener
3174 */
3175 public void addOnModeChangedListener(
3176 @NonNull @CallbackExecutor Executor executor,
3177 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003178 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3179 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003180 }
3181
3182 /**
3183 * Removes a previously added listener for changes to audio mode.
3184 * See {@link #getMode()}
3185 * @param listener
3186 */
3187 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003188 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003189 }
3190
3191 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003192 * Indicates if the platform supports a special call screening and call monitoring mode.
3193 * <p>
3194 * When this mode is supported, it is possible to perform call screening and monitoring
3195 * functions while other use cases like music or movie playback are active.
3196 * <p>
3197 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3198 * call screening mode.
3199 * <p>
3200 * If call screening mode is not supported, setting mode to
3201 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3202 * {@link #getMode()}.
3203 * @return true if call screening mode is supported, false otherwise.
3204 */
3205 public boolean isCallScreeningModeSupported() {
3206 final IAudioService service = getService();
3207 try {
3208 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003210 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 }
3212 }
3213
3214 /* modes for setMode/getMode/setRoute/getRoute */
3215 /**
3216 * Audio harware modes.
3217 */
3218 /**
3219 * Invalid audio mode.
3220 */
3221 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3222 /**
3223 * Current audio mode. Used to apply audio routing to current mode.
3224 */
3225 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3226 /**
3227 * Normal audio mode: not ringing and no call established.
3228 */
3229 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3230 /**
3231 * Ringing audio mode. An incoming is being signaled.
3232 */
3233 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3234 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003235 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 */
3237 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003238 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003239 * In communication audio mode. An audio/video chat or VoIP call is established.
3240 */
3241 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003242 /**
3243 * Call screening in progress. Call is connected and audio is accessible to call
3244 * screening applications but other audio use cases are still possible.
3245 */
3246 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3247
Eric Laurent1c3408f2021-11-09 12:09:54 +01003248 /**
3249 * A telephony call is established and its audio is being redirected to another device.
3250 */
3251 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3252
3253 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003254 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003255 * device.
3256 */
3257 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3258
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003259 /** @hide */
3260 @IntDef(flag = false, prefix = "MODE_", value = {
3261 MODE_NORMAL,
3262 MODE_RINGTONE,
3263 MODE_IN_CALL,
3264 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003265 MODE_CALL_SCREENING,
3266 MODE_CALL_REDIRECT,
3267 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003268 )
3269 @Retention(RetentionPolicy.SOURCE)
3270 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271
3272 /* Routing bits for setRouting/getRouting API */
3273 /**
3274 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003275 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3276 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 */
Eric Laurenta553c252009-07-17 12:17:14 -07003278 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003279 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003280 * Routing audio output to speaker
3281 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3282 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 */
Eric Laurenta553c252009-07-17 12:17:14 -07003284 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 /**
3286 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003287 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3288 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 */
3290 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3291 /**
3292 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003293 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3294 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 */
Eric Laurenta553c252009-07-17 12:17:14 -07003296 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 /**
3298 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003299 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3300 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 */
Eric Laurenta553c252009-07-17 12:17:14 -07003302 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003303 /**
3304 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003305 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3306 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 */
Eric Laurenta553c252009-07-17 12:17:14 -07003308 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 /**
3310 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003311 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3312 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 */
Eric Laurenta553c252009-07-17 12:17:14 -07003314 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315
3316 /**
3317 * Sets the audio routing for a specified mode
3318 *
3319 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3320 * @param routes bit vector of routes requested, created from one or
3321 * more of ROUTE_xxx types. Set bits indicate that route should be on
3322 * @param mask bit vector of routes to change, created from one or more of
3323 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003324 *
3325 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003326 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 */
Eric Laurenta553c252009-07-17 12:17:14 -07003328 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 }
3331
3332 /**
3333 * Returns the current audio routing bit vector for a specified mode.
3334 *
3335 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3336 * @return an audio route bit vector that can be compared with ROUTE_xxx
3337 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003338 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3339 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003341 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003343 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003344 }
3345
3346 /**
3347 * Checks whether any music is active.
3348 *
3349 * @return true if any music tracks are active.
3350 */
3351 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003352 final IAudioService service = getService();
3353 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003354 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003355 } catch (RemoteException e) {
3356 throw e.rethrowFromSystemServer();
3357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358 }
3359
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003360 /**
3361 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003362 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3363 * display). Note that BT audio sinks are not considered remote devices.
3364 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3365 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003366 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003367 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003368 final IAudioService service = getService();
3369 try {
3370 return service.isMusicActive(true /*remotely*/);
3371 } catch (RemoteException e) {
3372 throw e.rethrowFromSystemServer();
3373 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003374 }
3375
3376 /**
3377 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003378 * Checks whether the current audio focus is exclusive.
3379 * @return true if the top of the audio focus stack requested focus
3380 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3381 */
3382 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003383 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003384 try {
3385 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3386 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003387 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003388 }
3389 }
3390
3391 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003392 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003393 * An audio session identifier is a system wide unique identifier for a set of audio streams
3394 * (one or more mixed together).
3395 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3396 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3397 * session ID will be applied to the mixed audio content of the players that share the same
3398 * audio session.
3399 * <p>This method can for instance be used when creating one of the
3400 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3401 * or to specify a session for a speech synthesis utterance
3402 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003403 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003404 * system failed to generate a new session, a condition in which audio playback or recording
3405 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003406 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003407 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003408 int session = AudioSystem.newAudioSessionId();
3409 if (session > 0) {
3410 return session;
3411 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003412 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003413 return ERROR;
3414 }
3415 }
3416
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003417 /**
3418 * A special audio session ID to indicate that the audio session ID isn't known and the
3419 * framework should generate a new value. This can be used when building a new
3420 * {@link AudioTrack} instance with
3421 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3422 */
3423 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3424
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426 /*
3427 * Sets a generic audio configuration parameter. The use of these parameters
3428 * are platform dependant, see libaudio
3429 *
3430 * ** Temporary interface - DO NOT USE
3431 *
3432 * TODO: Replace with a more generic key:value get/set mechanism
3433 *
3434 * param key name of parameter to set. Must not be null.
3435 * param value value of parameter. Must not be null.
3436 */
3437 /**
3438 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003439 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 */
Eric Laurenta553c252009-07-17 12:17:14 -07003441 @Deprecated public void setParameter(String key, String value) {
3442 setParameters(key+"="+value);
3443 }
3444
3445 /**
3446 * Sets a variable number of parameter values to audio hardware.
3447 *
3448 * @param keyValuePairs list of parameters key value pairs in the form:
3449 * key1=value1;key2=value2;...
3450 *
3451 */
3452 public void setParameters(String keyValuePairs) {
3453 AudioSystem.setParameters(keyValuePairs);
3454 }
3455
3456 /**
William Escandeef429b62021-10-15 18:37:40 +02003457 * @hide
3458 */
3459 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3460 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3461 public void setHfpEnabled(boolean enable) {
3462 AudioSystem.setParameters("hfp_enable=" + enable);
3463 }
3464
3465 /**
3466 * @hide
3467 */
3468 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3469 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3470 public void setHfpVolume(int volume) {
3471 AudioSystem.setParameters("hfp_volume=" + volume);
3472 }
3473
3474 /**
3475 * @hide
3476 */
3477 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3478 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3479 public void setHfpSamplingRate(int rate) {
3480 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3481 }
3482
3483 /**
3484 * @hide
3485 */
3486 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3487 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3488 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3489 boolean hasWbsEnabled) {
3490 AudioSystem.setParameters("bt_headset_name=" + name
3491 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3492 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3493 }
3494
3495 /**
3496 * @hide
3497 */
3498 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3499 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3500 public void setA2dpSuspended(boolean enable) {
3501 AudioSystem.setParameters("A2dpSuspended=" + enable);
3502 }
3503
3504 /**
Rahul Sabnis215e5412022-12-21 16:03:07 -08003505 * Suspends the use of LE Audio.
3506 *
3507 * @param enable {@code true} to suspend le audio, {@code false} to unsuspend
3508 *
3509 * @hide
3510 */
3511 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3512 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3513 public void setLeAudioSuspended(boolean enable) {
3514 AudioSystem.setParameters("LeAudioSuspended=" + enable);
3515 }
3516
3517 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003518 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003519 *
3520 * @param keys list of parameters
3521 * @return list of parameters key value pairs in the form:
3522 * key1=value1;key2=value2;...
3523 */
3524 public String getParameters(String keys) {
3525 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 }
3527
3528 /* Sound effect identifiers */
3529 /**
3530 * Keyboard and direction pad click sound
3531 * @see #playSoundEffect(int)
3532 */
3533 public static final int FX_KEY_CLICK = 0;
3534 /**
3535 * Focus has moved up
3536 * @see #playSoundEffect(int)
3537 */
3538 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3539 /**
3540 * Focus has moved down
3541 * @see #playSoundEffect(int)
3542 */
3543 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3544 /**
3545 * Focus has moved left
3546 * @see #playSoundEffect(int)
3547 */
3548 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3549 /**
3550 * Focus has moved right
3551 * @see #playSoundEffect(int)
3552 */
3553 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3554 /**
3555 * IME standard keypress sound
3556 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003557 */
3558 public static final int FX_KEYPRESS_STANDARD = 5;
3559 /**
3560 * IME spacebar keypress sound
3561 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003562 */
3563 public static final int FX_KEYPRESS_SPACEBAR = 6;
3564 /**
3565 * IME delete keypress sound
3566 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567 */
3568 public static final int FX_KEYPRESS_DELETE = 7;
3569 /**
3570 * IME return_keypress sound
3571 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 */
3573 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003574
3575 /**
3576 * Invalid keypress sound
3577 * @see #playSoundEffect(int)
3578 */
3579 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003580
3581 /**
3582 * Back sound
3583 * @see #playSoundEffect(int)
3584 */
3585 public static final int FX_BACK = 10;
3586
3587 /**
3588 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003589 * <p>
3590 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3591 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003592 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3593 * @see #playSoundEffect(int)
3594 */
3595 public static final int FX_HOME = 11;
3596
3597 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003598 * @hide Navigation repeat sound 1
3599 * <p>
3600 * To be played by the framework when a focus navigation is repeatedly triggered
3601 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003602 * This is currently only used on TV devices.
3603 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3604 * @see #playSoundEffect(int)
3605 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003606 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003607
3608 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003609 * @hide Navigation repeat sound 2
3610 * <p>
3611 * To be played by the framework when a focus navigation is repeatedly triggered
3612 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003613 * This is currently only used on TV devices.
3614 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3615 * @see #playSoundEffect(int)
3616 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003617 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003618
3619 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003620 * @hide Navigation repeat sound 3
3621 * <p>
3622 * To be played by the framework when a focus navigation is repeatedly triggered
3623 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003624 * This is currently only used on TV devices.
3625 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3626 * @see #playSoundEffect(int)
3627 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003628 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003629
3630 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003631 * @hide Navigation repeat sound 4
3632 * <p>
3633 * To be played by the framework when a focus navigation is repeatedly triggered
3634 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003635 * This is currently only used on TV devices.
3636 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3637 * @see #playSoundEffect(int)
3638 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003639 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 /**
3642 * @hide Number of sound effects
3643 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003644 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003645 public static final int NUM_SOUND_EFFECTS = 16;
3646
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003647 /** @hide */
3648 @IntDef(prefix = { "FX_" }, value = {
3649 FX_KEY_CLICK,
3650 FX_FOCUS_NAVIGATION_UP,
3651 FX_FOCUS_NAVIGATION_DOWN,
3652 FX_FOCUS_NAVIGATION_LEFT,
3653 FX_FOCUS_NAVIGATION_RIGHT,
3654 FX_KEYPRESS_STANDARD,
3655 FX_KEYPRESS_SPACEBAR,
3656 FX_KEYPRESS_DELETE,
3657 FX_KEYPRESS_RETURN,
3658 FX_KEYPRESS_INVALID,
3659 FX_BACK
3660 })
3661 @Retention(RetentionPolicy.SOURCE)
3662 public @interface SystemSoundEffect {}
3663
Philip Junker7f1fdff2020-12-03 16:10:41 +01003664 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003665 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003666 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003667 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003668
3669 /**
3670 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003671 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3672 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003673 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003674 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003675 switch (n) {
3676 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003677 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003678 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003679 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003680 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003681 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003682 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003683 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003684 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003685 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003686 return -1;
3687 }
3688 }
3689
3690 /**
3691 * @hide
3692 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003693 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003694 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003695 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003696 } catch (RemoteException e) {
3697
3698 }
3699 }
3700
3701 /**
3702 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003703 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003704 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003705 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003706 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003707 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003708 } catch (RemoteException e) {
3709 throw e.rethrowFromSystemServer();
3710 }
3711 }
3712
3713 /**
3714 * @hide
3715 * @param enabled
3716 */
3717 public void setHomeSoundEffectEnabled(boolean enabled) {
3718 try {
3719 getService().setHomeSoundEffectEnabled(enabled);
3720 } catch (RemoteException e) {
3721
3722 }
3723 }
3724
3725 /**
3726 * @hide
3727 * @return true if the home sound effect is enabled
3728 */
3729 public boolean isHomeSoundEffectEnabled() {
3730 try {
3731 return getService().isHomeSoundEffectEnabled();
3732 } catch (RemoteException e) {
3733 throw e.rethrowFromSystemServer();
3734 }
3735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003736
3737 /**
3738 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003739 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003740 * NOTE: This version uses the UI settings to determine
3741 * whether sounds are heard or not.
3742 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003743 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003744 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003745 }
3746
3747 /**
3748 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003749 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003750 * @param userId The current user to pull sound settings from
3751 * NOTE: This version uses the UI settings to determine
3752 * whether sounds are heard or not.
3753 * @hide
3754 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003755 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003756 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3757 return;
3758 }
3759
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003760 if (delegateSoundEffectToVdm(effectType)) {
3761 return;
3762 }
3763
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003764 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003765 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003766 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003768 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769 }
3770 }
3771
3772 /**
3773 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003774 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003775 * @param volume Sound effect volume.
3776 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3777 * 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 -08003778 * NOTE: This version is for applications that have their own
3779 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003781 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003782 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3783 return;
3784 }
3785
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003786 if (delegateSoundEffectToVdm(effectType)) {
3787 return;
3788 }
3789
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003790 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 try {
3792 service.playSoundEffectVolume(effectType, volume);
3793 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003794 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003795 }
3796 }
3797
3798 /**
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003799 * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice}
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003800 * configured with custom device policy for audio. If there is such device, request to play
3801 * sound effect is forwarded to {@link VirtualDeviceManager}.
3802 *
3803 * @param effectType - The type of sound effect.
3804 * @return true if the request was forwarded to {@link VirtualDeviceManager} instance,
3805 * false otherwise.
3806 */
3807 private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003808 if (hasCustomPolicyVirtualDeviceContext()) {
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003809 VirtualDeviceManager vdm = getVirtualDeviceManager();
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003810 vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
3811 return true;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003812 }
3813 return false;
3814 }
3815
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003816 private boolean hasCustomPolicyVirtualDeviceContext() {
3817 if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) {
3818 return false;
3819 }
3820
3821 VirtualDeviceManager vdm = getVirtualDeviceManager();
3822 return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO)
3823 != DEVICE_POLICY_DEFAULT;
3824 }
3825
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003826 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 * Load Sound effects.
3828 * This method must be called when sound effects are enabled.
3829 */
3830 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003831 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 try {
3833 service.loadSoundEffects();
3834 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003835 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003836 }
3837 }
3838
3839 /**
3840 * Unload Sound effects.
3841 * This method can be called to free some memory when
3842 * sound effects are disabled.
3843 */
3844 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003845 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 try {
3847 service.unloadSoundEffects();
3848 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003849 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 }
3851 }
3852
Eric Laurent4050c932009-07-08 02:52:14 -07003853 /**
Andy Hung69836952020-03-26 01:00:15 -07003854 * @hide
3855 */
3856 public static String audioFocusToString(int focus) {
3857 switch (focus) {
3858 case AUDIOFOCUS_NONE:
3859 return "AUDIOFOCUS_NONE";
3860 case AUDIOFOCUS_GAIN:
3861 return "AUDIOFOCUS_GAIN";
3862 case AUDIOFOCUS_GAIN_TRANSIENT:
3863 return "AUDIOFOCUS_GAIN_TRANSIENT";
3864 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3865 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3866 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3867 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3868 case AUDIOFOCUS_LOSS:
3869 return "AUDIOFOCUS_LOSS";
3870 case AUDIOFOCUS_LOSS_TRANSIENT:
3871 return "AUDIOFOCUS_LOSS_TRANSIENT";
3872 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3873 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3874 default:
3875 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3876 }
3877 }
3878
3879 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003880 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003881 */
3882 public static final int AUDIOFOCUS_NONE = 0;
3883
3884 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003885 * 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 -07003886 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003887 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003888 */
3889 public static final int AUDIOFOCUS_GAIN = 1;
3890 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003891 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3892 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3893 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003894 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003895 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003896 */
3897 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003898 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003899 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003900 * amount of time, and where it is acceptable for other audio applications to keep playing
3901 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003902 * Examples of temporary changes are the playback of driving directions where playback of music
3903 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003904 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003905 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3906 */
3907 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3908 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003909 * Used to indicate a temporary request of audio focus, anticipated to last a short
3910 * amount of time, during which no other applications, or system components, should play
3911 * anything. Examples of exclusive and transient audio focus requests are voice
3912 * memo recording and speech recognition, during which the system shouldn't play any
3913 * notifications, and media playback should have paused.
3914 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3915 */
3916 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3917 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003918 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003919 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003920 */
3921 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3922 /**
3923 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003924 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003925 */
3926 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3927 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003928 * 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 -07003929 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3930 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003931 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003932 */
3933 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3934 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003935
3936 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003937 * Interface definition for a callback to be invoked when the audio focus of the system is
3938 * updated.
3939 */
3940 public interface OnAudioFocusChangeListener {
3941 /**
3942 * Called on the listener to notify it the audio focus for this listener has been changed.
3943 * The focusChange value indicates whether the focus was gained,
3944 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3945 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003946 * When losing focus, listeners can use the focus change information to decide what
3947 * behavior to adopt when losing focus. A music player could for instance elect to lower
3948 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3949 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003950 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003951 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003952 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003953 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003954 }
3955
3956 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003957 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3958 */
3959 private static class FocusRequestInfo {
3960 @NonNull final AudioFocusRequest mRequest;
3961 @Nullable final Handler mHandler;
3962 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3963 mRequest = afr;
3964 mHandler = handler;
3965 }
3966 }
3967
3968 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003969 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3970 * to actual listener objects.
3971 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003972 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003973 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3974 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003975
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003976 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003977 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003978 }
3979
3980 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003981 * Handler for events (audio focus change, recording config change) coming from the
3982 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003983 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003984 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003985 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003986
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003987 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003988 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003989 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003990 private final static int MSSG_FOCUS_CHANGE = 0;
3991 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003992 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003993
3994 /**
3995 * Helper class to handle the forwarding of audio service events to the appropriate listener
3996 */
3997 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003998 private final Handler mHandler;
3999
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004000 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004001 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004002 if (handler == null) {
4003 if ((looper = Looper.myLooper()) == null) {
4004 looper = Looper.getMainLooper();
4005 }
4006 } else {
4007 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004008 }
4009
4010 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004011 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004012 mHandler = new Handler(looper) {
4013 @Override
4014 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004015 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004016 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004017 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
4018 if (fri != null) {
4019 final OnAudioFocusChangeListener listener =
4020 fri.mRequest.getOnAudioFocusChangeListener();
4021 if (listener != null) {
4022 Log.d(TAG, "dispatching onAudioFocusChange("
4023 + msg.arg1 + ") to " + msg.obj);
4024 listener.onAudioFocusChange(msg.arg1);
4025 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004026 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004027 } break;
4028 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08004029 final RecordConfigChangeCallbackData cbData =
4030 (RecordConfigChangeCallbackData) msg.obj;
4031 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07004032 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004033 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004034 } break;
4035 case MSSG_PLAYBACK_CONFIG_CHANGE: {
4036 final PlaybackConfigChangeCallbackData cbData =
4037 (PlaybackConfigChangeCallbackData) msg.obj;
4038 if (cbData.mCb != null) {
4039 if (DEBUG) {
4040 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
4041 }
4042 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
4043 }
4044 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004045 default:
4046 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004047 }
4048 }
4049 };
4050 } else {
4051 mHandler = null;
4052 }
4053 }
4054
4055 Handler getHandler() {
4056 return mHandler;
4057 }
4058 }
4059
Glenn Kasten30c918c2011-11-10 17:56:41 -08004060 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004061 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004062 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004063 final FocusRequestInfo fri = findFocusRequestInfo(id);
4064 if (fri != null) {
4065 final OnAudioFocusChangeListener listener =
4066 fri.mRequest.getOnAudioFocusChangeListener();
4067 if (listener != null) {
4068 final Handler h = (fri.mHandler == null) ?
4069 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
4070 final Message m = h.obtainMessage(
4071 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
4072 id/*obj*/);
4073 h.sendMessage(m);
4074 }
4075 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004076 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004077
4078 @Override
4079 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
4080 synchronized (mFocusRequestsLock) {
4081 // TODO use generation counter as the key instead
4082 final BlockingFocusResultReceiver focusReceiver =
4083 mFocusRequestsAwaitingResult.remove(clientId);
4084 if (focusReceiver != null) {
4085 focusReceiver.notifyResult(requestResult);
4086 } else {
4087 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
4088 }
4089 }
4090 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004091 };
4092
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004093 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004094 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07004095 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004096 } else {
4097 return new String(this.toString() + l.toString());
4098 }
4099 }
4100
4101 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004102 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004103 * Registers a listener to be called when audio focus changes and keeps track of the associated
4104 * focus request (including Handler to use for the listener).
4105 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004106 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004107 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
4108 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
4109 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
4110 new ServiceEventHandlerDelegate(h).getHandler());
4111 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4112 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004113 }
4114
4115 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004116 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004117 * Causes the specified listener to not be called anymore when focus is gained or lost.
4118 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004119 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004120 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004121 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004122 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004123 }
4124
4125
4126 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004127 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004128 */
4129 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
4130 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004131 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004132 */
4133 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004134 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004135 * A focus change request whose granting is delayed: the request was successful, but the
4136 * requester will only be granted audio focus once the condition that prevented immediate
4137 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004138 * See {@link #requestAudioFocus(AudioFocusRequest)} and
4139 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004140 */
4141 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004142
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004143 /** @hide */
4144 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
4145 AUDIOFOCUS_REQUEST_FAILED,
4146 AUDIOFOCUS_REQUEST_GRANTED,
4147 AUDIOFOCUS_REQUEST_DELAYED }
4148 )
4149 @Retention(RetentionPolicy.SOURCE)
4150 public @interface FocusRequestResult {}
4151
4152 /**
4153 * @hide
4154 * code returned when a synchronous focus request on the client-side is to be blocked
4155 * until the external audio focus policy decides on the response for the client
4156 */
4157 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
4158
4159 /**
4160 * Timeout duration in ms when waiting on an external focus policy for the result for a
4161 * focus request
4162 */
Weilin Xu1017d432022-06-08 00:27:52 +00004163 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004164
4165 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4166
4167 private final Object mFocusRequestsLock = new Object();
4168 /**
4169 * Map of all receivers of focus request results, one per unresolved focus request.
4170 * Receivers are added before sending the request to the external focus policy,
4171 * and are removed either after receiving the result, or after the timeout.
4172 * This variable is lazily initialized.
4173 */
4174 @GuardedBy("mFocusRequestsLock")
4175 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4176
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004177
4178 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004179 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004180 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004181 * @param l the listener to be notified of audio focus changes
4182 * @param streamType the main audio stream type affected by the focus request
4183 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4184 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004185 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004186 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4187 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004188 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4189 * that benefits from the system not playing disruptive sounds like notifications, for
4190 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004191 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004192 * as the playback of a song or a video.
4193 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004194 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004195 */
4196 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004197 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4198 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004199 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004200
4201 try {
4202 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4203 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4204 // AUDIOFOCUS_FLAG_DELAY_OK flag
4205 status = requestAudioFocus(l,
4206 new AudioAttributes.Builder()
4207 .setInternalLegacyStreamType(streamType).build(),
4208 durationHint,
4209 0 /* flags, legacy behavior */);
4210 } catch (IllegalArgumentException e) {
4211 Log.e(TAG, "Audio focus request denied due to ", e);
4212 }
4213
4214 return status;
4215 }
4216
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004217 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004218 /**
4219 * @hide
4220 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4221 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4222 * the system is in a state where focus cannot change, but be granted focus later when
4223 * this condition ends.
4224 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004225 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004226 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004227 /**
4228 * @hide
4229 * Use this flag when requesting audio focus to indicate that the requester
4230 * will pause its media playback (if applicable) when losing audio focus with
4231 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4232 * <br>On some platforms, the ducking may be handled without the application being aware of it
4233 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4234 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4235 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4236 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004237 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004238 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4239 /**
4240 * @hide
4241 * Use this flag to lock audio focus so granting is temporarily disabled.
4242 * <br>This flag can only be used by owners of a registered
4243 * {@link android.media.audiopolicy.AudioPolicy} in
4244 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4245 */
4246 @SystemApi
4247 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004248
4249 /**
4250 * @hide
4251 * flag set on test API calls,
4252 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004253 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004254 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004255 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004256 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4257 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004258 /** @hide */
4259 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004260 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004261
4262 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004263 * Request audio focus.
4264 * See the {@link AudioFocusRequest} for information about the options available to configure
4265 * your request, and notification of focus gain and loss.
4266 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4267 * requested.
4268 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4269 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4270 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4271 * is requested without building the {@link AudioFocusRequest} with
4272 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4273 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004274 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004275 */
4276 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004277 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004278 }
4279
4280 /**
4281 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4282 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4283 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4284 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4285 * @throws IllegalArgumentException if passed a null argument
4286 */
4287 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4288 if (focusRequest == null) {
4289 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4290 }
4291 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4292 focusRequest.getAudioAttributes());
4293 }
4294
4295 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004296 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004297 * Request audio focus.
4298 * Send a request to obtain the audio focus. This method differs from
4299 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4300 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004301 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4302 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4303 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4304 * requesting audio focus.
4305 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4306 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4307 * for the playback of driving directions, or notifications sounds.
4308 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4309 * the previous focus owner to keep playing if it ducks its audio output.
4310 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4311 * that benefits from the system not playing disruptive sounds like notifications, for
4312 * usecases such as voice memo recording, or speech recognition.
4313 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4314 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004315 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4316 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004317 * <br>Use 0 when not using any flags for the request, which behaves like
4318 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4319 * focus is granted immediately, or the grant request fails because the system is in a
4320 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004321 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4322 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4323 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4324 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4325 * @throws IllegalArgumentException
4326 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004327 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004328 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004329 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004330 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004331 int durationHint,
4332 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004333 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4334 throw new IllegalArgumentException("Invalid flags 0x"
4335 + Integer.toHexString(flags).toUpperCase());
4336 }
4337 return requestAudioFocus(l, requestAttributes, durationHint,
4338 flags & AUDIOFOCUS_FLAGS_APPS,
4339 null /* no AudioPolicy*/);
4340 }
4341
4342 /**
4343 * @hide
4344 * Request or lock audio focus.
4345 * This method is to be used by system components that have registered an
4346 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4347 * so focus granting is temporarily disabled.
4348 * @param l see the description of the same parameter in
4349 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4350 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4351 * requesting audio focus.
4352 * @param durationHint see the description of the same parameter in
4353 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4354 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004355 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004356 * <br>Use 0 when not using any flags for the request, which behaves like
4357 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4358 * focus is granted immediately, or the grant request fails because the system is in a
4359 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004360 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4361 * focus, or null.
4362 * @return see the description of the same return value in
4363 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4364 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004365 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004366 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004367 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004368 @RequiresPermission(anyOf= {
4369 android.Manifest.permission.MODIFY_PHONE_STATE,
4370 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4371 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004372 public int requestAudioFocus(OnAudioFocusChangeListener l,
4373 @NonNull AudioAttributes requestAttributes,
4374 int durationHint,
4375 int flags,
4376 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004377 // parameter checking
4378 if (requestAttributes == null) {
4379 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4380 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004381 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004382 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004383 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004384 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004385 throw new IllegalArgumentException("Illegal flags 0x"
4386 + Integer.toHexString(flags).toUpperCase());
4387 }
4388 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4389 throw new IllegalArgumentException(
4390 "Illegal null focus listener when flagged as accepting delayed focus grant");
4391 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004392 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4393 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4394 throw new IllegalArgumentException(
4395 "Illegal null focus listener when flagged as pausing instead of ducking");
4396 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004397 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4398 throw new IllegalArgumentException(
4399 "Illegal null audio policy when locking audio focus");
4400 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004401
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004402 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004403 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004404 .setAudioAttributes(requestAttributes)
4405 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4406 == AUDIOFOCUS_FLAG_DELAY_OK)
4407 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4408 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4409 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4410 .build();
4411 return requestAudioFocus(afr, ap);
4412 }
4413
4414 /**
4415 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004416 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4417 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4418 * @param afr the parameters of the request
4419 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4420 * @param clientFakeUid the UID of the client, here an arbitrary int,
4421 * doesn't have to be a real UID
4422 * @param clientTargetSdk the target SDK used by the client
4423 * @return return code indicating status of the request
4424 */
4425 @TestApi
4426 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4427 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4428 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4429 Objects.requireNonNull(afr);
4430 Objects.requireNonNull(clientFakeId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004431 int status;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004432 try {
Oscar Azucena3209c342022-05-13 19:08:14 -07004433 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004434 afr.getFocusGain(),
4435 mICallBack,
4436 mAudioFocusDispatcher,
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004437 clientFakeId, "com.android.test.fakeclient",
4438 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4439 clientFakeUid, clientTargetSdk);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004440 } catch (RemoteException e) {
4441 throw e.rethrowFromSystemServer();
4442 }
Weilin Xu1017d432022-06-08 00:27:52 +00004443 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4444 // default path with no external focus policy
4445 return status;
4446 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004447
Weilin Xu1017d432022-06-08 00:27:52 +00004448 BlockingFocusResultReceiver focusReceiver;
4449 synchronized (mFocusRequestsLock) {
4450 focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
4451 }
4452
4453 return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004454 }
4455
4456 /**
4457 * @hide
4458 * Test API to abandon audio focus for an arbitrary client.
4459 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4460 * @param afr the parameters used for the request
4461 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4462 * would be requesting
4463 * @return return code indicating status of the request
4464 */
4465 @TestApi
4466 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4467 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4468 @NonNull String clientFakeId) {
4469 Objects.requireNonNull(afr);
4470 Objects.requireNonNull(clientFakeId);
4471 try {
4472 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4473 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4474 } catch (RemoteException e) {
4475 throw e.rethrowFromSystemServer();
4476 }
4477 }
4478
4479 /**
4480 * @hide
4481 * Return the duration of the fade out applied when a player of the given AudioAttributes
4482 * is losing audio focus
4483 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4484 * @return a duration in ms, 0 indicates no fade out is applied
4485 */
4486 @TestApi
4487 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4488 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4489 {
4490 Objects.requireNonNull(aa);
4491 try {
4492 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4493 } catch (RemoteException e) {
4494 throw e.rethrowFromSystemServer();
4495 }
4496 }
4497
4498 /**
4499 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004500 * Request or lock audio focus.
4501 * This method is to be used by system components that have registered an
4502 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4503 * so focus granting is temporarily disabled.
4504 * @param afr see the description of the same parameter in
4505 * {@link #requestAudioFocus(AudioFocusRequest)}
4506 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4507 * focus, or null.
4508 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4509 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4510 * @throws NullPointerException if the AudioFocusRequest is null
4511 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4512 */
4513 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004514 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004515 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4516 if (afr == null) {
4517 throw new NullPointerException("Illegal null AudioFocusRequest");
4518 }
4519 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4520 if (afr.locksFocus() && ap == null) {
4521 throw new IllegalArgumentException(
4522 "Illegal null audio policy when locking audio focus");
4523 }
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004524
4525 if (hasCustomPolicyVirtualDeviceContext()) {
4526 // If the focus request was made within context associated with VirtualDevice
4527 // configured with custom device policy for audio, bypass audio service focus handling.
4528 // The custom device policy for audio means that audio associated with this device
4529 // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice
4530 // shouldn't affect non-virtual audio tracks (and vice versa).
4531 return AUDIOFOCUS_REQUEST_GRANTED;
4532 }
4533
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004534 registerAudioFocusRequest(afr);
4535 final IAudioService service = getService();
4536 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004537 int sdk;
4538 try {
4539 sdk = getContext().getApplicationInfo().targetSdkVersion;
4540 } catch (NullPointerException e) {
4541 // some tests don't have a Context
4542 sdk = Build.VERSION.SDK_INT;
4543 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004544
4545 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
Weilin Xu1017d432022-06-08 00:27:52 +00004546 BlockingFocusResultReceiver focusReceiver;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004547 synchronized (mFocusRequestsLock) {
Weilin Xu1017d432022-06-08 00:27:52 +00004548
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004549 try {
4550 // TODO status contains result and generation counter for ext policy
4551 status = service.requestAudioFocus(afr.getAudioAttributes(),
4552 afr.getFocusGain(), mICallBack,
4553 mAudioFocusDispatcher,
4554 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004555 getContext().getOpPackageName() /* package name */,
4556 getContext().getAttributionTag(),
4557 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004558 ap != null ? ap.cb() : null,
4559 sdk);
4560 } catch (RemoteException e) {
4561 throw e.rethrowFromSystemServer();
4562 }
Weilin Xu1017d432022-06-08 00:27:52 +00004563 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4564 // default path with no external focus policy
4565 return status;
4566 }
4567 focusReceiver = addClientIdToFocusReceiverLocked(clientId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004568 }
4569
Weilin Xu1017d432022-06-08 00:27:52 +00004570 return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver);
4571 }
4572
4573 @GuardedBy("mFocusRequestsLock")
4574 private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) {
4575 BlockingFocusResultReceiver focusReceiver;
4576 if (mFocusRequestsAwaitingResult == null) {
4577 mFocusRequestsAwaitingResult =
4578 new HashMap<String, BlockingFocusResultReceiver>(1);
4579 }
4580 focusReceiver = new BlockingFocusResultReceiver(clientId);
4581 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
4582 return focusReceiver;
Oscar Azucena3209c342022-05-13 19:08:14 -07004583 }
4584
4585 private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
Weilin Xu1017d432022-06-08 00:27:52 +00004586 BlockingFocusResultReceiver focusReceiver) {
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004587 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4588 if (DEBUG && !focusReceiver.receivedResult()) {
Oscar Azucena3209c342022-05-13 19:08:14 -07004589 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
4590 + " response from ext policy timed out, denying request");
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004591 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004592
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004593 synchronized (mFocusRequestsLock) {
4594 mFocusRequestsAwaitingResult.remove(clientId);
4595 }
4596 return focusReceiver.requestResult();
4597 }
4598
4599 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4600 private static final class SafeWaitObject {
4601 private boolean mQuit = false;
4602
4603 public void safeNotify() {
4604 synchronized (this) {
4605 mQuit = true;
4606 this.notify();
4607 }
4608 }
4609
4610 public void safeWait(long millis) throws InterruptedException {
4611 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4612 synchronized (this) {
4613 while (!mQuit) {
4614 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4615 if (timeToWait < 0) { break; }
4616 this.wait(timeToWait);
4617 }
4618 }
4619 }
4620 }
4621
4622 private static final class BlockingFocusResultReceiver {
4623 private final SafeWaitObject mLock = new SafeWaitObject();
4624 @GuardedBy("mLock")
4625 private boolean mResultReceived = false;
4626 // request denied by default (e.g. timeout)
4627 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4628 private final String mFocusClientId;
4629
4630 BlockingFocusResultReceiver(String clientId) {
4631 mFocusClientId = clientId;
4632 }
4633
4634 boolean receivedResult() { return mResultReceived; }
4635 int requestResult() { return mFocusRequestResult; }
4636
4637 void notifyResult(int requestResult) {
4638 synchronized (mLock) {
4639 mResultReceived = true;
4640 mFocusRequestResult = requestResult;
4641 mLock.safeNotify();
4642 }
4643 }
4644
4645 public void waitForResult(long timeOutMs) {
4646 synchronized (mLock) {
4647 if (mResultReceived) {
4648 // the result was received before waiting
4649 return;
4650 }
4651 try {
4652 mLock.safeWait(timeOutMs);
4653 } catch (InterruptedException e) { }
4654 }
4655 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004656 }
4657
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004658 /**
4659 * @hide
4660 * Used internally by telephony package to request audio focus. Will cause the focus request
4661 * to be associated with the "voice communication" identifier only used in AudioService
4662 * to identify this use case.
4663 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4664 * the establishment of the call
4665 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4666 * media applications resume after a call
4667 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004668 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004669 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004670 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004671 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004672 service.requestAudioFocus(new AudioAttributes.Builder()
4673 .setInternalLegacyStreamType(streamType).build(),
4674 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004675 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004676 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004677 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004678 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004679 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004680 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004681 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004682 }
4683 }
4684
4685 /**
4686 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004687 * Return the volume ramping time for a sound to be played after the given focus request,
4688 * and to play a sound of the given attributes
4689 * @param focusGain
4690 * @param attr
4691 * @return
4692 */
4693 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004694 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004695 try {
4696 return service.getFocusRampTimeMs(focusGain, attr);
4697 } catch (RemoteException e) {
4698 throw e.rethrowFromSystemServer();
4699 }
4700 }
4701
4702 /**
4703 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004704 * Set the result to the audio focus request received through
4705 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4706 * @param afi the information about the focus requester
4707 * @param requestResult the result to the focus request to be passed to the requester
4708 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4709 */
4710 @SystemApi
4711 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4712 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4713 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4714 if (afi == null) {
4715 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4716 }
4717 if (ap == null) {
4718 throw new IllegalArgumentException("Illegal null AudioPolicy");
4719 }
4720 final IAudioService service = getService();
4721 try {
4722 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4723 } catch (RemoteException e) {
4724 throw e.rethrowFromSystemServer();
4725 }
4726 }
4727
4728 /**
4729 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004730 * Notifies an application with a focus listener of gain or loss of audio focus.
4731 * This method can only be used by owners of an {@link AudioPolicy} configured with
4732 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4733 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4734 * that was received by the {@code AudioPolicy} through
4735 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4736 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4737 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4738 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4739 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4740 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4741 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4742 * <br>For the focus gain, the change type should be the same as the app requested.
4743 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4744 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4745 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4746 * if there was an error sending the request.
4747 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4748 */
4749 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004750 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004751 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4752 @NonNull AudioPolicy ap) {
4753 if (afi == null) {
4754 throw new NullPointerException("Illegal null AudioFocusInfo");
4755 }
4756 if (ap == null) {
4757 throw new NullPointerException("Illegal null AudioPolicy");
4758 }
4759 final IAudioService service = getService();
4760 try {
4761 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4762 } catch (RemoteException e) {
4763 throw e.rethrowFromSystemServer();
4764 }
4765 }
4766
4767 /**
4768 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004769 * Used internally by telephony package to abandon audio focus, typically after a call or
4770 * when ringing ends and the call is rejected or not answered.
4771 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4772 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004773 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004774 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004775 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004776 try {
John Spurlock61560172015-02-06 19:46:04 -05004777 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004778 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004779 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004780 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004781 }
4782 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004783
4784 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004785 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4786 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004787 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004788 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004789 */
4790 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004791 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4792 }
4793
4794 /**
4795 * @hide
4796 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4797 * @param l the listener with which focus was requested.
4798 * @param aa the {@link AudioAttributes} with which audio focus was requested
4799 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004800 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004801 */
4802 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004803 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4804 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004805 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004806 if (hasCustomPolicyVirtualDeviceContext()) {
4807 // If this AudioManager instance is running within VirtualDevice context configured
4808 // with custom device policy for audio, the audio focus handling is bypassed.
4809 return AUDIOFOCUS_REQUEST_GRANTED;
4810 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004811 unregisterAudioFocusRequest(l);
4812 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004813 try {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004814 return service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004815 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004816 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004817 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004818 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004819 }
4820
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004821 //====================================================================
4822 // Remote Control
4823 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004824 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004825 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4826 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004827 * in the application manifest. The package of the component must match that of
4828 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004829 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004830 */
RoboErikb214efb2014-07-24 13:20:30 -07004831 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004832 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004833 if (eventReceiver == null) {
4834 return;
4835 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004836 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004837 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4838 "receiver and context package names don't match");
4839 return;
4840 }
4841 // construct a PendingIntent for the media button and register it
4842 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4843 // the associated intent will be handled by the component being registered
4844 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004845 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004846 0/*requestCode, ignored*/, mediaButtonIntent,
4847 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004848 registerMediaButtonIntent(pi, eventReceiver);
4849 }
4850
4851 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004852 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4853 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4854 * the buttons to go to any PendingIntent. Note that you should only use this form if
4855 * you know you will continue running for the full time until unregistering the
4856 * PendingIntent.
4857 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004858 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4859 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4860 * media button that was pressed.
4861 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004862 */
RoboErikb214efb2014-07-24 13:20:30 -07004863 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004864 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4865 if (eventReceiver == null) {
4866 return;
4867 }
4868 registerMediaButtonIntent(eventReceiver, null);
4869 }
4870
4871 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004872 * @hide
4873 * no-op if (pi == null) or (eventReceiver == null)
4874 */
4875 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004876 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004877 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4878 return;
4879 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004880 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4881 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004882 }
4883
4884 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004885 * Unregister the receiver of MEDIA_BUTTON intents.
4886 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4887 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004888 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004889 */
RoboErikb214efb2014-07-24 13:20:30 -07004890 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004891 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004892 if (eventReceiver == null) {
4893 return;
4894 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004895 // construct a PendingIntent for the media button and unregister it
4896 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4897 // the associated intent will be handled by the component being registered
4898 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004899 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004900 0/*requestCode, ignored*/, mediaButtonIntent,
4901 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004902 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004903 }
4904
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004905 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004906 * Unregister the receiver of MEDIA_BUTTON intents.
4907 * @param eventReceiver same PendingIntent that was registed with
4908 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004909 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004910 */
RoboErikb214efb2014-07-24 13:20:30 -07004911 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004912 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4913 if (eventReceiver == null) {
4914 return;
4915 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004916 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004917 }
4918
4919 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004920 * @hide
4921 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004922 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004923 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004924 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004925 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004926
4927 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004928 * Registers the remote control client for providing information to display on the remote
4929 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004930 * @param rcClient The remote control client from which remote controls will receive
4931 * information to display.
4932 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004933 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004934 */
RoboErikb214efb2014-07-24 13:20:30 -07004935 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004936 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004937 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004938 return;
4939 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004940 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004941 }
4942
4943 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004944 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004945 * remote controls.
4946 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004947 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004948 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004949 */
RoboErikb214efb2014-07-24 13:20:30 -07004950 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004951 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004952 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004953 return;
4954 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004955 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004956 }
4957
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004958 /**
RoboErika66c40b2014-08-15 15:21:41 -07004959 * Registers a {@link RemoteController} instance for it to receive media
4960 * metadata updates and playback state information from applications using
4961 * {@link RemoteControlClient}, and control their playback.
4962 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004963 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004964 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004965 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004966 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004967 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004968 * @return true if the {@link RemoteController} was successfully registered,
4969 * false if an error occurred, due to an internal system error, or
4970 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004971 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004972 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4973 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004974 */
RoboErikb214efb2014-07-24 13:20:30 -07004975 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004976 public boolean registerRemoteController(RemoteController rctlr) {
4977 if (rctlr == null) {
4978 return false;
4979 }
RoboErik430fc482014-06-12 15:49:20 -07004980 rctlr.startListeningToSessions();
4981 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004982 }
4983
4984 /**
RoboErika66c40b2014-08-15 15:21:41 -07004985 * Unregisters a {@link RemoteController}, causing it to no longer receive
4986 * media metadata and playback state information, and no longer be capable
4987 * of controlling playback.
4988 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004989 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004990 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004991 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4992 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004993 */
RoboErikb214efb2014-07-24 13:20:30 -07004994 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004995 public void unregisterRemoteController(RemoteController rctlr) {
4996 if (rctlr == null) {
4997 return;
4998 }
RoboErik430fc482014-06-12 15:49:20 -07004999 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005000 }
5001
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005002
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005003 //====================================================================
5004 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005005 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005006 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005007 * Register the given {@link AudioPolicy}.
5008 * This call is synchronous and blocks until the registration process successfully completed
5009 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005010 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005011 * @return {@link #ERROR} if there was an error communicating with the registration service
5012 * or if the user doesn't have the required
5013 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
5014 * {@link #SUCCESS} otherwise.
5015 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005016 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06005017 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005018 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005019 return registerAudioPolicyStatic(policy);
5020 }
5021
5022 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005023 if (policy == null) {
5024 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5025 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005026 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005027 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005028 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005029 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07005030 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
5031 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005032 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005033 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005034 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005035 } else {
5036 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005037 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005038 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005039 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005040 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005041 }
5042 return SUCCESS;
5043 }
5044
5045 /**
5046 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005047 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005048 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005049 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005050 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06005051 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005052 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005053 unregisterAudioPolicyAsyncStatic(policy);
5054 }
5055
5056 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005057 if (policy == null) {
5058 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5059 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005060 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005061 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005062 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005063 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005064 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005065 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005066 }
5067 }
5068
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005069 /**
5070 * @hide
5071 * Unregisters an {@link AudioPolicy} synchronously.
5072 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
5073 * associated with mixes of this policy.
5074 * @param policy the non-null {@link AudioPolicy} to unregister.
5075 */
5076 @SystemApi
5077 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5078 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
5079 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
5080 final IAudioService service = getService();
5081 try {
5082 policy.invalidateCaptorsAndInjectors();
5083 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005084 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005085 } catch (RemoteException e) {
5086 throw e.rethrowFromSystemServer();
5087 }
5088 }
5089
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07005090 /**
5091 * @hide
5092 * @return true if an AudioPolicy was previously registered
5093 */
5094 @TestApi
5095 public boolean hasRegisteredDynamicPolicy() {
5096 final IAudioService service = getService();
5097 try {
5098 return service.hasRegisteredDynamicPolicy();
5099 } catch (RemoteException e) {
5100 throw e.rethrowFromSystemServer();
5101 }
5102 }
5103
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005104 //====================================================================
5105 // Notification of playback activity & playback configuration
5106 /**
5107 * Interface for receiving update notifications about the playback activity on the system.
5108 * Extend this abstract class and register it with
5109 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
5110 * to be notified.
5111 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
5112 * configuration.
5113 * @see AudioPlaybackConfiguration
5114 */
5115 public static abstract class AudioPlaybackCallback {
5116 /**
5117 * Called whenever the playback activity and configuration has changed.
5118 * @param configs list containing the results of
5119 * {@link AudioManager#getActivePlaybackConfigurations()}.
5120 */
5121 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
5122 }
5123
5124 private static class AudioPlaybackCallbackInfo {
5125 final AudioPlaybackCallback mCb;
5126 final Handler mHandler;
5127 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
5128 mCb = cb;
5129 mHandler = handler;
5130 }
5131 }
5132
5133 private final static class PlaybackConfigChangeCallbackData {
5134 final AudioPlaybackCallback mCb;
5135 final List<AudioPlaybackConfiguration> mConfigs;
5136
5137 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
5138 List<AudioPlaybackConfiguration> configs) {
5139 mCb = cb;
5140 mConfigs = configs;
5141 }
5142 }
5143
5144 /**
5145 * Register a callback to be notified of audio playback changes through
5146 * {@link AudioPlaybackCallback}
5147 * @param cb non-null callback to register
5148 * @param handler the {@link Handler} object for the thread on which to execute
5149 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5150 * {@link Looper} will be used.
5151 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005152 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
5153 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005154 {
5155 if (cb == null) {
5156 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5157 }
5158
5159 synchronized(mPlaybackCallbackLock) {
5160 // lazy initialization of the list of playback callbacks
5161 if (mPlaybackCallbackList == null) {
5162 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
5163 }
5164 final int oldCbCount = mPlaybackCallbackList.size();
5165 if (!hasPlaybackCallback_sync(cb)) {
5166 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
5167 new ServiceEventHandlerDelegate(handler).getHandler()));
5168 final int newCbCount = mPlaybackCallbackList.size();
5169 if ((oldCbCount == 0) && (newCbCount > 0)) {
5170 // register binder for callbacks
5171 try {
5172 getService().registerPlaybackCallback(mPlayCb);
5173 } catch (RemoteException e) {
5174 throw e.rethrowFromSystemServer();
5175 }
5176 }
5177 } else {
5178 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
5179 + "registered callback");
5180 }
5181 }
5182 }
5183
5184 /**
5185 * Unregister an audio playback callback previously registered with
5186 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5187 * @param cb non-null callback to unregister
5188 */
5189 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
5190 if (cb == null) {
5191 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5192 }
5193 synchronized(mPlaybackCallbackLock) {
5194 if (mPlaybackCallbackList == null) {
5195 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5196 + " that was never registered");
5197 return;
5198 }
5199 final int oldCbCount = mPlaybackCallbackList.size();
5200 if (removePlaybackCallback_sync(cb)) {
5201 final int newCbCount = mPlaybackCallbackList.size();
5202 if ((oldCbCount > 0) && (newCbCount == 0)) {
5203 // unregister binder for callbacks
5204 try {
5205 getService().unregisterPlaybackCallback(mPlayCb);
5206 } catch (RemoteException e) {
5207 throw e.rethrowFromSystemServer();
5208 }
5209 }
5210 } else {
5211 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5212 + " already unregistered or never registered");
5213 }
5214 }
5215 }
5216
5217 /**
5218 * Returns the current active audio playback configurations of the device
5219 * @return a non-null list of playback configurations. An empty list indicates there is no
5220 * playback active when queried.
5221 * @see AudioPlaybackConfiguration
5222 */
5223 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5224 final IAudioService service = getService();
5225 try {
5226 return service.getActivePlaybackConfigurations();
5227 } catch (RemoteException e) {
5228 throw e.rethrowFromSystemServer();
5229 }
5230 }
5231
5232 /**
5233 * All operations on this list are sync'd on mPlaybackCallbackLock.
5234 * List is lazy-initialized in
5235 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5236 * List can be null.
5237 */
5238 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5239 private final Object mPlaybackCallbackLock = new Object();
5240
5241 /**
5242 * Must be called synchronized on mPlaybackCallbackLock
5243 */
5244 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5245 if (mPlaybackCallbackList != null) {
5246 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5247 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5248 return true;
5249 }
5250 }
5251 }
5252 return false;
5253 }
5254
5255 /**
5256 * Must be called synchronized on mPlaybackCallbackLock
5257 */
5258 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5259 if (mPlaybackCallbackList != null) {
5260 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5261 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5262 mPlaybackCallbackList.remove(i);
5263 return true;
5264 }
5265 }
5266 }
5267 return false;
5268 }
5269
5270 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005271 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005272 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5273 boolean flush) {
5274 if (flush) {
5275 Binder.flushPendingCommands();
5276 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005277 synchronized(mPlaybackCallbackLock) {
5278 if (mPlaybackCallbackList != null) {
5279 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5280 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5281 if (arci.mHandler != null) {
5282 final Message m = arci.mHandler.obtainMessage(
5283 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5284 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5285 arci.mHandler.sendMessage(m);
5286 }
5287 }
5288 }
5289 }
5290 }
5291
5292 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005293
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005294 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005295 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005296 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005297 * Interface for receiving update notifications about the recording configuration. Extend
5298 * this abstract class and register it with
5299 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5300 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005301 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5302 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005303 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005304 */
5305 public static abstract class AudioRecordingCallback {
5306 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005307 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005308 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005309 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005310 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005311 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005312 }
5313
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005314 private static class AudioRecordingCallbackInfo {
5315 final AudioRecordingCallback mCb;
5316 final Handler mHandler;
5317 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5318 mCb = cb;
5319 mHandler = handler;
5320 }
5321 }
5322
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005323 private final static class RecordConfigChangeCallbackData {
5324 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005325 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005326
5327 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005328 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005329 mCb = cb;
5330 mConfigs = configs;
5331 }
5332 }
5333
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005334 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005335 * Register a callback to be notified of audio recording changes through
5336 * {@link AudioRecordingCallback}
5337 * @param cb non-null callback to register
5338 * @param handler the {@link Handler} object for the thread on which to execute
5339 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5340 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005341 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005342 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5343 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005344 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005345 if (cb == null) {
5346 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5347 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005348
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005349 synchronized(mRecordCallbackLock) {
5350 // lazy initialization of the list of recording callbacks
5351 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005352 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005353 }
5354 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005355 if (!hasRecordCallback_sync(cb)) {
5356 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5357 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005358 final int newCbCount = mRecordCallbackList.size();
5359 if ((oldCbCount == 0) && (newCbCount > 0)) {
5360 // register binder for callbacks
5361 final IAudioService service = getService();
5362 try {
5363 service.registerRecordingCallback(mRecCb);
5364 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005365 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005366 }
5367 }
5368 } else {
5369 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5370 + "registered callback");
5371 }
5372 }
5373 }
5374
5375 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005376 * Unregister an audio recording callback previously registered with
5377 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5378 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005379 */
5380 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5381 if (cb == null) {
5382 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5383 }
5384 synchronized(mRecordCallbackLock) {
5385 if (mRecordCallbackList == null) {
5386 return;
5387 }
5388 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005389 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005390 final int newCbCount = mRecordCallbackList.size();
5391 if ((oldCbCount > 0) && (newCbCount == 0)) {
5392 // unregister binder for callbacks
5393 final IAudioService service = getService();
5394 try {
5395 service.unregisterRecordingCallback(mRecCb);
5396 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005397 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005398 }
5399 }
5400 } else {
5401 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5402 + " already unregistered or never registered");
5403 }
5404 }
5405 }
5406
5407 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005408 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005409 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005410 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005411 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005412 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005413 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005414 final IAudioService service = getService();
5415 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005416 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005417 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005418 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005419 }
5420 }
5421
5422 /**
5423 * constants for the recording events, to keep in sync
5424 * with frameworks/av/include/media/AudioPolicy.h
5425 */
5426 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005427 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005428 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005429 public static final int RECORD_CONFIG_EVENT_START = 0;
5430 /** @hide */
5431 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5432 /** @hide */
5433 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5434 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005435 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005436 /**
5437 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5438 */
5439 /** @hide */
5440 public static final int RECORD_RIID_INVALID = -1;
5441 /** @hide */
5442 public static final int RECORDER_STATE_STARTED = 0;
5443 /** @hide */
5444 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005445
5446 /**
5447 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005448 * List is lazy-initialized in
5449 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005450 * List can be null.
5451 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005452 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005453 private final Object mRecordCallbackLock = new Object();
5454
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005455 /**
5456 * Must be called synchronized on mRecordCallbackLock
5457 */
5458 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5459 if (mRecordCallbackList != null) {
5460 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5461 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5462 return true;
5463 }
5464 }
5465 }
5466 return false;
5467 }
5468
5469 /**
5470 * Must be called synchronized on mRecordCallbackLock
5471 */
5472 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5473 if (mRecordCallbackList != null) {
5474 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5475 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5476 mRecordCallbackList.remove(i);
5477 return true;
5478 }
5479 }
5480 }
5481 return false;
5482 }
5483
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005484 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005485 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005486 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005487 synchronized(mRecordCallbackLock) {
5488 if (mRecordCallbackList != null) {
5489 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5490 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5491 if (arci.mHandler != null) {
5492 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005493 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5494 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005495 arci.mHandler.sendMessage(m);
5496 }
5497 }
5498 }
5499 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005500 }
5501
5502 };
5503
5504 //=====================================================================
5505
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005506 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005507 * @hide
5508 * Reload audio settings. This method is called by Settings backup
5509 * agent when audio settings are restored and causes the AudioService
5510 * to read and apply restored settings.
5511 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005512 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005513 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005514 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005515 try {
5516 service.reloadAudioSettings();
5517 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005518 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005519 }
5520 }
5521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005522 /**
5523 * {@hide}
5524 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005525 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005526
5527 /**
5528 * Checks whether the phone is in silent mode, with or without vibrate.
5529 *
5530 * @return true if phone is in silent mode, with or without vibrate.
5531 *
5532 * @see #getRingerMode()
5533 *
5534 * @hide pending API Council approval
5535 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005536 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005537 public boolean isSilentMode() {
5538 int ringerMode = getRingerMode();
5539 boolean silentMode =
5540 (ringerMode == RINGER_MODE_SILENT) ||
5541 (ringerMode == RINGER_MODE_VIBRATE);
5542 return silentMode;
5543 }
5544
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005545 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5546 // class is not used by other parts of the framework, which instead use definitions and methods
5547 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5548
Eric Laurent948d3272014-05-16 15:18:45 -07005549 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005550 * The audio device code for representing "no device." */
5551 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5552 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005553 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005554 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5555 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5556 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5557 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005558 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005559 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005560 /** @hide
5561 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005562 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005563 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005564 /** @hide
5565 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005566 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005567 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005568 /** @hide
5569 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005570 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005571 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005572 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005573 * The audio output device code for a USB headphone with attached microphone */
5574 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5575 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005576 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005577 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005578 /** @hide
5579 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5580 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005581 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005582 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005583 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5584 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005585 /** @hide
5586 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005587 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5588 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005589 /** @hide
5590 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005591 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005592 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005593 /** @hide
5594 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005595 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005596 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5597 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005598 /** @hide
5599 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005600 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005601 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5602 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005603 /** @hide
5604 * The audio output device code for S/PDIF (legacy) or HDMI
5605 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005606 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005607 /** @hide
5608 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005609 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005610 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5611 /** @hide
5612 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005613 * docking station
5614 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005615 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005616 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005617 /** @hide
5618 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005619 * docking station
5620 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005621 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005622 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005623 /** @hide
5624 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005625 * mode and the Android device in USB device mode
5626 */
5627 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005628 /** @hide
5629 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005630 * mode and the Android device in USB host mode
5631 */
5632 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005633 /** @hide
5634 * The audio output device code for projection output.
5635 */
5636 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5637 /** @hide
5638 * The audio output device code the telephony voice TX path.
5639 */
5640 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5641 /** @hide
5642 * The audio output device code for an analog jack with line impedance detected.
5643 */
5644 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5645 /** @hide
5646 * The audio output device code for HDMI Audio Return Channel.
5647 */
5648 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5649 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005650 * The audio output device code for HDMI enhanced Audio Return Channel.
5651 */
5652 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5653 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005654 * The audio output device code for S/PDIF digital connection.
5655 */
5656 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5657 /** @hide
5658 * The audio output device code for built-in FM transmitter.
5659 */
5660 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5661 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005662 * The audio output device code for echo reference injection point.
5663 */
5664 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5665 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005666 * The audio output device code for a BLE audio headset.
5667 */
5668 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5669 /** @hide
5670 * The audio output device code for a BLE audio speaker.
5671 */
5672 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5673 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01005674 * The audio output device code for a BLE audio brodcast group.
5675 */
5676 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
5677 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005678 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005679 * used in the future in a set method to select whatever default device is chosen by the
5680 * platform-specific implementation.
5681 */
5682 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5683
Eric Laurent948d3272014-05-16 15:18:45 -07005684 /** @hide
5685 * The audio input device code for default built-in microphone
5686 */
5687 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5688 /** @hide
5689 * The audio input device code for a Bluetooth SCO headset
5690 */
5691 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5692 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5693 /** @hide
5694 * The audio input device code for wired headset microphone
5695 */
5696 public static final int DEVICE_IN_WIRED_HEADSET =
5697 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5698 /** @hide
5699 * The audio input device code for HDMI
5700 */
5701 public static final int DEVICE_IN_HDMI =
5702 AudioSystem.DEVICE_IN_HDMI;
5703 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005704 * The audio input device code for HDMI ARC
5705 */
5706 public static final int DEVICE_IN_HDMI_ARC =
5707 AudioSystem.DEVICE_IN_HDMI_ARC;
5708
5709 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005710 * The audio input device code for HDMI EARC
5711 */
5712 public static final int DEVICE_IN_HDMI_EARC =
5713 AudioSystem.DEVICE_IN_HDMI_EARC;
5714
5715 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005716 * The audio input device code for telephony voice RX path
5717 */
5718 public static final int DEVICE_IN_TELEPHONY_RX =
5719 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5720 /** @hide
5721 * The audio input device code for built-in microphone pointing to the back
5722 */
5723 public static final int DEVICE_IN_BACK_MIC =
5724 AudioSystem.DEVICE_IN_BACK_MIC;
5725 /** @hide
5726 * The audio input device code for analog from a docking station
5727 */
5728 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5729 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5730 /** @hide
5731 * The audio input device code for digital from a docking station
5732 */
5733 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5734 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5735 /** @hide
5736 * The audio input device code for a USB audio accessory. The accessory is in USB host
5737 * mode and the Android device in USB device mode
5738 */
5739 public static final int DEVICE_IN_USB_ACCESSORY =
5740 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5741 /** @hide
5742 * The audio input device code for a USB audio device. The device is in USB device
5743 * mode and the Android device in USB host mode
5744 */
5745 public static final int DEVICE_IN_USB_DEVICE =
5746 AudioSystem.DEVICE_IN_USB_DEVICE;
5747 /** @hide
5748 * The audio input device code for a FM radio tuner
5749 */
5750 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5751 /** @hide
5752 * The audio input device code for a TV tuner
5753 */
5754 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5755 /** @hide
5756 * The audio input device code for an analog jack with line impedance detected
5757 */
5758 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5759 /** @hide
5760 * The audio input device code for a S/PDIF digital connection
5761 */
5762 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005763 /** @hide
5764 * The audio input device code for audio loopback
5765 */
5766 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005767 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005768 * The audio input device code for an echo reference capture point.
5769 */
5770 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5771 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005772 * The audio input device code for a BLE audio headset.
5773 */
5774 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005775
5776 /**
5777 * Return true if the device code corresponds to an output device.
5778 * @hide
5779 */
5780 public static boolean isOutputDevice(int device)
5781 {
5782 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5783 }
5784
5785 /**
5786 * Return true if the device code corresponds to an input device.
5787 * @hide
5788 */
5789 public static boolean isInputDevice(int device)
5790 {
5791 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5792 }
5793
5794
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005795 /**
5796 * Return the enabled devices for the specified output stream type.
5797 *
5798 * @param streamType The stream type to query. One of
5799 * {@link #STREAM_VOICE_CALL},
5800 * {@link #STREAM_SYSTEM},
5801 * {@link #STREAM_RING},
5802 * {@link #STREAM_MUSIC},
5803 * {@link #STREAM_ALARM},
5804 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005805 * {@link #STREAM_DTMF},
5806 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005807 *
5808 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5809 * stream. Zero or more of
5810 * {@link #DEVICE_OUT_EARPIECE},
5811 * {@link #DEVICE_OUT_SPEAKER},
5812 * {@link #DEVICE_OUT_WIRED_HEADSET},
5813 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5814 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5815 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5816 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5817 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5818 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5819 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005820 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005821 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5822 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005823 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5824 * {@link #DEVICE_OUT_USB_DEVICE}.
5825 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5826 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5827 * {@link #DEVICE_OUT_LINE}.
5828 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005829 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005830 * {@link #DEVICE_OUT_SPDIF}.
5831 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005832 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5833 *
5834 * The implementation may support additional device codes beyond those listed, so
5835 * the application should ignore any bits which it does not recognize.
5836 * Note that the information may be imprecise when the implementation
5837 * cannot distinguish whether a particular device is enabled.
5838 *
Andy Hungb11e4c72021-04-13 19:31:00 -07005839 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
5840 * will have multi-bit device types.
5841 * Prefer to use {@link #getDevicesForAttributes()} instead,
5842 * noting that getDevicesForStream() has a few small discrepancies
5843 * for better volume handling.
5844 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005845 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005846 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07005847 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005848 public int getDevicesForStream(int streamType) {
5849 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07005850 case STREAM_VOICE_CALL:
5851 case STREAM_SYSTEM:
5852 case STREAM_RING:
5853 case STREAM_MUSIC:
5854 case STREAM_ALARM:
5855 case STREAM_NOTIFICATION:
5856 case STREAM_DTMF:
5857 case STREAM_ACCESSIBILITY:
5858 final IAudioService service = getService();
5859 try {
5860 return service.getDeviceMaskForStream(streamType);
5861 } catch (RemoteException e) {
5862 throw e.rethrowFromSystemServer();
5863 }
5864 default:
5865 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005866 }
5867 }
5868
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005869 /**
5870 * @hide
5871 * Get the audio devices that would be used for the routing of the given audio attributes.
5872 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5873 * @return an empty list if there was an issue with the request, a list of audio devices
5874 * otherwise (typically one device, except for duplicated paths).
5875 */
5876 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005877 @RequiresPermission(anyOf = {
5878 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5879 android.Manifest.permission.QUERY_AUDIO_STATE
5880 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005881 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005882 @NonNull AudioAttributes attributes) {
5883 Objects.requireNonNull(attributes);
5884 final IAudioService service = getService();
5885 try {
5886 return service.getDevicesForAttributes(attributes);
5887 } catch (RemoteException e) {
5888 throw e.rethrowFromSystemServer();
5889 }
5890 }
5891
Paul Wangebadb692022-12-15 20:40:19 +00005892 // Each listener corresponds to a unique callback stub because each listener can subscribe to
5893 // different AudioAttributes.
5894 private final ConcurrentHashMap<OnDevicesForAttributesChangedListener,
5895 IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub =
5896 new ConcurrentHashMap<>();
5897
5898 private static final class IDevicesForAttributesCallbackStub
5899 extends IDevicesForAttributesCallback.Stub {
5900 ListenerInfo<OnDevicesForAttributesChangedListener> mInfo;
5901
5902 IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener,
5903 @NonNull Executor executor) {
5904 mInfo = new ListenerInfo<>(listener, executor);
5905 }
5906
5907 public void register(boolean register, AudioAttributes attributes) {
5908 try {
5909 if (register) {
5910 getService().addOnDevicesForAttributesChangedListener(attributes, this);
5911 } else {
5912 getService().removeOnDevicesForAttributesChangedListener(this);
5913 }
5914 } catch (RemoteException e) {
5915 throw e.rethrowFromSystemServer();
5916 }
5917 }
5918
5919 @Override
5920 public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume,
5921 List<AudioDeviceAttributes> devices) {
5922 // forVolume is ignored. The case where it is `true` is not handled.
5923 mInfo.mExecutor.execute(() ->
5924 mInfo.mListener.onDevicesForAttributesChanged(
5925 attributes, devices));
5926 }
5927 }
5928
5929 /**
5930 * @hide
5931 * Interface to be notified of when routing changes for the registered audio attributes.
5932 */
5933 @SystemApi
5934 public interface OnDevicesForAttributesChangedListener {
5935 /**
5936 * Called on the listener to indicate that the audio devices for the given audio
5937 * attributes have changed.
5938 * @param attributes the {@link AudioAttributes} whose routing changed
5939 * @param devices a list of newly routed audio devices
5940 */
5941 void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
5942 @NonNull List<AudioDeviceAttributes> devices);
5943 }
5944
5945 /**
5946 * @hide
5947 * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}.
5948 * @param attributes the {@link AudioAttributes} to listen for routing changes
5949 * @param executor
5950 * @param listener
5951 */
5952 @SystemApi
5953 @RequiresPermission(anyOf = {
5954 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5955 android.Manifest.permission.QUERY_AUDIO_STATE
5956 })
5957 public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
5958 @NonNull @CallbackExecutor Executor executor,
5959 @NonNull OnDevicesForAttributesChangedListener listener) {
5960 Objects.requireNonNull(attributes);
5961 Objects.requireNonNull(executor);
5962 Objects.requireNonNull(listener);
5963
5964 synchronized (mDevicesForAttributesListenerToStub) {
5965 IDevicesForAttributesCallbackStub callbackStub =
5966 mDevicesForAttributesListenerToStub.get(listener);
5967
5968 if (callbackStub == null) {
5969 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor);
5970 mDevicesForAttributesListenerToStub.put(listener, callbackStub);
5971 }
5972
5973 callbackStub.register(true, attributes);
5974 }
5975 }
5976
5977 /**
5978 * @hide
5979 * Removes a previously registered listener for being notified of routing changes for the given
5980 * {@link AudioAttributes}.
5981 * @param listener
5982 */
5983 @SystemApi
5984 @RequiresPermission(anyOf = {
5985 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5986 android.Manifest.permission.QUERY_AUDIO_STATE
5987 })
5988 public void removeOnDevicesForAttributesChangedListener(
5989 @NonNull OnDevicesForAttributesChangedListener listener) {
5990 Objects.requireNonNull(listener);
5991
5992 synchronized (mDevicesForAttributesListenerToStub) {
5993 IDevicesForAttributesCallbackStub callbackStub =
5994 mDevicesForAttributesListenerToStub.get(listener);
5995 if (callbackStub != null) {
5996 callbackStub.register(false, null /* attributes */);
5997 }
5998
5999 mDevicesForAttributesListenerToStub.remove(listener);
6000 }
6001 }
6002
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006003 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01006004 * Get the audio devices that would be used for the routing of the given audio attributes.
6005 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
6006 * the specified {@link AudioAttributes}.
6007 * The audio routing can change if audio devices are physically connected or disconnected or
6008 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
6009 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6010 * @return an empty list if there was an issue with the request, a list of
6011 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
6012 */
6013 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
6014 @NonNull AudioAttributes attributes) {
6015 final List<AudioDeviceAttributes> devicesForAttributes;
6016 try {
6017 Objects.requireNonNull(attributes);
6018 final IAudioService service = getService();
6019 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
6020 } catch (Exception e) {
6021 Log.i(TAG, "No audio devices available for specified attributes.");
6022 return Collections.emptyList();
6023 }
6024
6025 // Map from AudioDeviceAttributes to AudioDeviceInfo
6026 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
6027 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
6028 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
6029 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
6030 if (deviceForAttributes.getType() == deviceInfo.getType()
6031 && TextUtils.equals(deviceForAttributes.getAddress(),
6032 deviceInfo.getAddress())) {
6033 deviceInfosForAttributes.add(deviceInfo);
6034 }
6035 }
6036 }
6037 return Collections.unmodifiableList(deviceInfosForAttributes);
6038 }
6039
6040 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006041 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006042 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02006043 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
6044 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006045 */
6046 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
6047 /**
6048 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006049 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02006050 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006051 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006052 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006053 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
6054 /**
6055 * @hide
6056 * Volume behavior for an audio device where the volume is always set to provide no attenuation
6057 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006058 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006059 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006060 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006061 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
6062 /**
6063 * @hide
6064 * Volume behavior for an audio device where the volume is either set to muted, or to provide
6065 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006066 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006067 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006068 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006069 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
6070 /**
6071 * @hide
6072 * Volume behavior for an audio device where no software attenuation is applied, and
6073 * the volume is kept synchronized between the host and the device itself through a
6074 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02006075 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006076 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006077 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006078 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
6079 /**
6080 * @hide
6081 * Volume behavior for an audio device where no software attenuation is applied, and
6082 * the volume is kept synchronized between the host and the device itself through a
6083 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
6084 * normal vs in phone call).
6085 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02006086 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006087 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006088 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006089 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
6090
6091 /** @hide */
6092 @IntDef({
6093 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6094 DEVICE_VOLUME_BEHAVIOR_FULL,
6095 DEVICE_VOLUME_BEHAVIOR_FIXED,
6096 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6097 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
6098 })
6099 @Retention(RetentionPolicy.SOURCE)
6100 public @interface DeviceVolumeBehavior {}
6101
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006102 /** @hide */
6103 @IntDef({
6104 DEVICE_VOLUME_BEHAVIOR_UNSET,
6105 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6106 DEVICE_VOLUME_BEHAVIOR_FULL,
6107 DEVICE_VOLUME_BEHAVIOR_FIXED,
6108 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6109 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
6110 })
6111 @Retention(RetentionPolicy.SOURCE)
6112 public @interface DeviceVolumeBehaviorState {}
6113
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006114 /**
6115 * @hide
6116 * Throws IAE on an invalid volume behavior value
6117 * @param volumeBehavior behavior value to check
6118 */
6119 public static void enforceValidVolumeBehavior(int volumeBehavior) {
6120 switch (volumeBehavior) {
6121 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
6122 case DEVICE_VOLUME_BEHAVIOR_FULL:
6123 case DEVICE_VOLUME_BEHAVIOR_FIXED:
6124 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
6125 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
6126 return;
6127 default:
6128 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
6129 }
6130 }
6131
6132 /**
6133 * @hide
6134 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02006135 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
6136 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
6137 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
6138 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
6139 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
6140 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006141 * @param deviceVolumeBehavior one of the device behaviors
6142 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006143 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006144 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6145 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
6146 @DeviceVolumeBehavior int deviceVolumeBehavior) {
6147 // verify arguments (validity of device type is enforced in server)
6148 Objects.requireNonNull(device);
6149 enforceValidVolumeBehavior(deviceVolumeBehavior);
6150 // communicate with service
6151 final IAudioService service = getService();
6152 try {
6153 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
6154 mApplicationContext.getOpPackageName());
6155 } catch (RemoteException e) {
6156 throw e.rethrowFromSystemServer();
6157 }
6158 }
6159
6160 /**
6161 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006162 * Returns the volume device behavior for the given audio device
6163 * @param device the audio device
6164 * @return the volume behavior for the device
6165 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006166 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006167 @RequiresPermission(anyOf = {
6168 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
6169 android.Manifest.permission.QUERY_AUDIO_STATE
6170 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02006171 public @DeviceVolumeBehavior
6172 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006173 // verify arguments (validity of device type is enforced in server)
6174 Objects.requireNonNull(device);
6175 // communicate with service
6176 final IAudioService service = getService();
6177 try {
6178 return service.getDeviceVolumeBehavior(device);
6179 } catch (RemoteException e) {
6180 throw e.rethrowFromSystemServer();
6181 }
6182 }
6183
kholoud mohamed37839212021-03-15 16:49:06 +00006184 /**
6185 * @hide
6186 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
6187 */
6188 @TestApi
6189 @RequiresPermission(anyOf = {
6190 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
6191 android.Manifest.permission.QUERY_AUDIO_STATE
6192 })
6193 public boolean isFullVolumeDevice() {
6194 final AudioAttributes attributes = new AudioAttributes.Builder()
6195 .setUsage(AudioAttributes.USAGE_MEDIA)
6196 .build();
6197 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
6198 for (AudioDeviceAttributes device : devices) {
6199 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
6200 return true;
6201 }
6202 }
6203 return false;
6204 }
6205
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006206 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006207 * Indicate wired accessory connection state change.
6208 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
6209 * @param state new connection state: 1 connected, 0 disconnected
6210 * @param name device name
6211 * {@hide}
6212 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006213 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07006214 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair7b72c392022-04-04 13:25:46 +02006215 public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
6216 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006217 setWiredDeviceConnectionState(attributes, state);
6218 }
6219
6220 /**
6221 * Indicate wired accessory connection state change and attributes.
6222 * @param state new connection state: 1 connected, 0 disconnected
6223 * @param attributes attributes of the connected device
6224 * {@hide}
6225 */
6226 @UnsupportedAppUsage
6227 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6228 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07006229 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006230 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006231 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07006232 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006233 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006234 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006235 }
6236 }
6237
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00006238 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006239 * Indicate wired accessory connection state change.
6240 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
6241 * @param connected true for connected, false for disconnected
6242 * {@hide}
6243 */
6244 @TestApi
6245 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6246 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
6247 boolean connected) {
6248 try {
6249 getService().setTestDeviceConnectionState(device, connected);
6250 } catch (RemoteException e) {
6251 throw e.rethrowFromSystemServer();
6252 }
6253 }
6254
6255 /**
wescande7c17ba0c2021-07-30 16:46:14 +02006256 * Indicate Bluetooth profile connection state change.
6257 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
6258 * <code>previousDevice</code>
6259 * This operation is asynchronous.
6260 *
6261 * @param newDevice Bluetooth device connected or null if there is no new devices
6262 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
6263 * devices
William Escandeac11d772022-01-25 18:01:15 +01006264 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006265 * {@hide}
6266 */
wescande7c17ba0c2021-07-30 16:46:14 +02006267 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6268 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
6269 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01006270 @Nullable BluetoothDevice previousDevice,
6271 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006272 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006273 try {
wescande7c17ba0c2021-07-30 16:46:14 +02006274 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006275 } catch (RemoteException e) {
6276 throw e.rethrowFromSystemServer();
6277 }
6278 }
6279
Jeff Sharkey098d5802012-04-26 17:30:34 -07006280 /** {@hide} */
6281 public IRingtonePlayer getRingtonePlayer() {
6282 try {
6283 return getService().getRingtonePlayer();
6284 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006285 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006286 }
6287 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006288
6289 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006290 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07006291 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
6292 * should use this value as a default, and offer the user the option to override it.
6293 * The low latency output stream is typically either the device's primary output stream,
6294 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006295 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006296 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006297 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
6298 "android.media.property.OUTPUT_SAMPLE_RATE";
6299
6300 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006301 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07006302 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
6303 * should use this value as a minimum, and offer the user the option to override it.
6304 * The low latency output stream is typically either the device's primary output stream,
6305 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006306 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006307 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006308 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
6309 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
6310
6311 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07006312 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
6313 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6314 */
6315 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6316 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6317
6318 /**
6319 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6320 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6321 */
6322 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6323 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6324
6325 /**
ragoa7cc59c2015-12-02 11:31:15 -08006326 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6327 * available and supported with the expected frequency range and level response.
6328 */
6329 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6330 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6331 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006332 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006333 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006334 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6335 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006336 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6337 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6338 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006339 * @return A string representing the associated value for that property key,
6340 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006341 */
6342 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006343 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6344 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6345 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6346 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6347 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6348 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006349 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006350 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6351 // not found.
6352 return String.valueOf(getContext().getResources().getBoolean(
6353 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006354 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006355 return String.valueOf(getContext().getResources().getBoolean(
6356 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006357 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6358 return String.valueOf(getContext().getResources().getBoolean(
6359 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006360 } else {
6361 // null or unknown key
6362 return null;
6363 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006364 }
6365
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006366 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006367 * @hide
6368 * Sets an additional audio output device delay in milliseconds.
6369 *
6370 * The additional output delay is a request to the output device to
6371 * delay audio presentation (generally with respect to video presentation for better
6372 * synchronization).
6373 * It may not be supported by all output devices,
6374 * and typically increases the audio latency by the amount of additional
6375 * audio delay requested.
6376 *
6377 * If additional audio delay is supported by an audio output device,
6378 * it is expected to be supported for all output streams (and configurations)
6379 * opened on that device.
6380 *
6381 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006382 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006383 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6384 * @return true if successful, false if the device does not support output device delay
6385 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6386 */
6387 @SystemApi
6388 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6389 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006390 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006391 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006392 try {
6393 return getService().setAdditionalOutputDeviceDelay(
6394 new AudioDeviceAttributes(device), delayMillis);
6395 } catch (RemoteException e) {
6396 throw e.rethrowFromSystemServer();
6397 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006398 }
6399
6400 /**
6401 * @hide
6402 * Returns the current additional audio output device delay in milliseconds.
6403 *
6404 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6405 * @return the additional output device delay. This is a non-negative number.
6406 * {@code 0} is returned if unsupported.
6407 */
6408 @SystemApi
6409 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006410 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006411 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006412 try {
6413 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6414 } catch (RemoteException e) {
6415 throw e.rethrowFromSystemServer();
6416 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006417 }
6418
6419 /**
6420 * @hide
6421 * Returns the maximum additional audio output device delay in milliseconds.
6422 *
6423 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6424 * @return the maximum output device delay in milliseconds that can be set.
6425 * This is a non-negative number
6426 * representing the additional audio delay supported for the device.
6427 * {@code 0} is returned if unsupported.
6428 */
6429 @SystemApi
6430 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006431 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006432 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006433 try {
6434 return getService().getMaxAdditionalOutputDeviceDelay(
6435 new AudioDeviceAttributes(device));
6436 } catch (RemoteException e) {
6437 throw e.rethrowFromSystemServer();
6438 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006439 }
6440
6441 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006442 * Returns the estimated latency for the given stream type in milliseconds.
6443 *
6444 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6445 * a better solution.
6446 * @hide
6447 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006448 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006449 public int getOutputLatency(int streamType) {
6450 return AudioSystem.getOutputLatency(streamType);
6451 }
6452
John Spurlock3346a802014-05-20 16:25:37 -04006453 /**
6454 * Registers a global volume controller interface. Currently limited to SystemUI.
6455 *
6456 * @hide
6457 */
6458 public void setVolumeController(IVolumeController controller) {
6459 try {
6460 getService().setVolumeController(controller);
6461 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006462 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006463 }
6464 }
6465
6466 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006467 * Notify audio manager about volume controller visibility changes.
6468 * Currently limited to SystemUI.
6469 *
6470 * @hide
6471 */
6472 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6473 try {
6474 getService().notifyVolumeControllerVisible(controller, visible);
6475 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006476 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006477 }
6478 }
6479
6480 /**
John Spurlock3346a802014-05-20 16:25:37 -04006481 * Only useful for volume controllers.
6482 * @hide
6483 */
John Spurlock3346a802014-05-20 16:25:37 -04006484 public boolean isStreamAffectedByRingerMode(int streamType) {
6485 try {
6486 return getService().isStreamAffectedByRingerMode(streamType);
6487 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006488 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006489 }
6490 }
6491
6492 /**
6493 * Only useful for volume controllers.
6494 * @hide
6495 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006496 public boolean isStreamAffectedByMute(int streamType) {
6497 try {
6498 return getService().isStreamAffectedByMute(streamType);
6499 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006500 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006501 }
6502 }
6503
6504 /**
6505 * Only useful for volume controllers.
6506 * @hide
6507 */
John Spurlock3346a802014-05-20 16:25:37 -04006508 public void disableSafeMediaVolume() {
6509 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006510 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006511 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006512 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006513 }
6514 }
Eric Laurenta198a292014-02-18 16:26:17 -08006515
6516 /**
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00006517 * @hide
6518 * Lower media volume to RS1
6519 */
6520 public void lowerVolumeToRs1() {
6521 try {
6522 getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName());
6523 } catch (RemoteException e) {
6524 throw e.rethrowFromSystemServer();
6525 }
6526 }
6527
6528 /**
6529 * @hide
6530 * Sound dose warning at every 100% of dose during integration window
6531 */
6532 public static final int CSD_WARNING_DOSE_REACHED_1X = 1;
6533 /**
6534 * @hide
6535 * Sound dose warning when 500% of dose is reached during integration window
6536 */
6537 public static final int CSD_WARNING_DOSE_REPEATED_5X = 2;
6538 /**
6539 * @hide
6540 * Sound dose warning after a momentary exposure event
6541 */
6542 public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3;
6543 /**
6544 * @hide
6545 * Sound dose warning at every 100% of dose during integration window
6546 */
6547 public static final int CSD_WARNING_ACCUMULATION_START = 4;
6548
6549 /** @hide */
6550 @IntDef(flag = false, value = {
6551 CSD_WARNING_DOSE_REACHED_1X,
6552 CSD_WARNING_DOSE_REPEATED_5X,
6553 CSD_WARNING_MOMENTARY_EXPOSURE,
6554 CSD_WARNING_ACCUMULATION_START }
6555 )
6556 @Retention(RetentionPolicy.SOURCE)
6557 public @interface CsdWarning {}
6558
6559 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006560 * Only useful for volume controllers.
6561 * @hide
6562 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006563 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006564 public void setRingerModeInternal(int ringerMode) {
6565 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006566 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006567 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006568 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006569 }
6570 }
6571
6572 /**
6573 * Only useful for volume controllers.
6574 * @hide
6575 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006576 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006577 public int getRingerModeInternal() {
6578 try {
6579 return getService().getRingerModeInternal();
6580 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006581 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006582 }
6583 }
6584
6585 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006586 * Only useful for volume controllers.
6587 * @hide
6588 */
6589 public void setVolumePolicy(VolumePolicy policy) {
6590 try {
6591 getService().setVolumePolicy(policy);
6592 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006593 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006594 }
6595 }
6596
6597 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006598 * Set Hdmi Cec system audio mode.
6599 *
6600 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006601 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006602 * @hide
6603 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006604 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006605 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006606 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006607 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006608 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006609 }
6610 }
6611
6612 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006613 * Returns true if Hdmi Cec system audio mode is supported.
6614 *
6615 * @hide
6616 */
6617 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006618 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006619 public boolean isHdmiSystemAudioSupported() {
6620 try {
6621 return getService().isHdmiSystemAudioSupported();
6622 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006623 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006624 }
6625 }
6626
6627 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006628 * Return codes for listAudioPorts(), createAudioPatch() ...
6629 */
6630
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006631 /** @hide */
6632 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006633 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006634 /**
6635 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006636 */
6637 public static final int ERROR = AudioSystem.ERROR;
6638 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006639 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006640 */
6641 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6642 /** @hide
6643 */
6644 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6645 /** @hide
6646 */
6647 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6648 /** @hide
6649 */
6650 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006651 /**
6652 * An error code indicating that the object reporting it is no longer valid and needs to
6653 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006654 */
6655 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6656
6657 /**
6658 * Returns a list of descriptors for all audio ports managed by the audio framework.
6659 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6660 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6661 * See AudioPort for a list of attributes of each audio port.
6662 * @param ports An AudioPort ArrayList where the list will be returned.
6663 * @hide
6664 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006665 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006666 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006667 return updateAudioPortCache(ports, null, null);
6668 }
6669
6670 /**
6671 * Returns a list of descriptors for all audio ports managed by the audio framework as
6672 * it was before the last update calback.
6673 * @param ports An AudioPort ArrayList where the list will be returned.
6674 * @hide
6675 */
6676 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6677 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006678 }
6679
6680 /**
6681 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6682 * @see listAudioPorts(ArrayList<AudioPort>)
6683 * @hide
6684 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006685 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006686 if (devices == null) {
6687 return ERROR_BAD_VALUE;
6688 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006689 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006690 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006691 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006692 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006693 }
6694 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006695 }
6696
6697 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006698 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6699 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6700 * @hide
6701 */
6702 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6703 if (devices == null) {
6704 return ERROR_BAD_VALUE;
6705 }
6706 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6707 int status = updateAudioPortCache(null, null, ports);
6708 if (status == SUCCESS) {
6709 filterDevicePorts(ports, devices);
6710 }
6711 return status;
6712 }
6713
6714 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6715 ArrayList<AudioDevicePort> devices) {
6716 devices.clear();
6717 for (int i = 0; i < ports.size(); i++) {
6718 if (ports.get(i) instanceof AudioDevicePort) {
6719 devices.add((AudioDevicePort)ports.get(i));
6720 }
6721 }
6722 }
6723
6724 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006725 * Create a connection between two or more devices. The framework will reject the request if
6726 * device types are not compatible or the implementation does not support the requested
6727 * configuration.
6728 * NOTE: current implementation is limited to one source and one sink per patch.
6729 * @param patch AudioPatch array where the newly created patch will be returned.
6730 * As input, if patch[0] is not null, the specified patch will be replaced by the
6731 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6732 * patch and allows the implementation to optimize transitions.
6733 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6734 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6735 *
6736 * @return - {@link #SUCCESS} if connection is successful.
6737 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6738 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6739 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6740 * a patch.
6741 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6742 * - {@link #ERROR} if patch cannot be connected for any other reason.
6743 *
6744 * patch[0] contains the newly created patch
6745 * @hide
6746 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006747 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006748 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006749 AudioPortConfig[] sources,
6750 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006751 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006752 }
6753
6754 /**
6755 * Releases an existing audio patch connection.
6756 * @param patch The audio patch to disconnect.
6757 * @return - {@link #SUCCESS} if disconnection is successful.
6758 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6759 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6760 * a patch.
6761 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6762 * - {@link #ERROR} if patch cannot be released for any other reason.
6763 * @hide
6764 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006765 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006766 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006767 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006768 }
6769
6770 /**
6771 * List all existing connections between audio ports.
6772 * @param patches An AudioPatch array where the list will be returned.
6773 * @hide
6774 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006775 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006776 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006777 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006778 }
6779
6780 /**
6781 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6782 * AudioGain.buildConfig()
6783 * @hide
6784 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006785 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006786 if (port == null || gain == null) {
6787 return ERROR_BAD_VALUE;
6788 }
6789 AudioPortConfig activeConfig = port.activeConfig();
6790 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6791 activeConfig.channelMask(), activeConfig.format(), gain);
6792 config.mConfigMask = AudioPortConfig.GAIN;
6793 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006794 }
6795
6796 /**
6797 * Listener registered by client to be notified upon new audio port connections,
6798 * disconnections or attributes update.
6799 * @hide
6800 */
6801 public interface OnAudioPortUpdateListener {
6802 /**
6803 * Callback method called upon audio port list update.
6804 * @param portList the updated list of audio ports
6805 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006806 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006807
6808 /**
6809 * Callback method called upon audio patch list update.
6810 * @param patchList the updated list of audio patches
6811 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006812 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006813
6814 /**
6815 * Callback method called when the mediaserver dies
6816 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006817 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006818 }
6819
6820 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006821 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006822 * @hide
6823 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006824 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006825 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006826 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006827 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006828 }
6829
6830 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006831 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006832 * @hide
6833 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006834 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006835 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006836 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006837 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006838
6839 //
6840 // AudioPort implementation
6841 //
6842
Cole Faust7da659b2022-10-15 21:33:29 -07006843 private static final int AUDIOPORT_GENERATION_INIT = 0;
6844 private static Object sAudioPortGenerationLock = new Object();
6845 @GuardedBy("sAudioPortGenerationLock")
6846 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
6847 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
6848 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
6849 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006850
Eric Laurentf076db42015-01-14 13:23:27 -08006851 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006852 int generation;
Cole Faust7da659b2022-10-15 21:33:29 -07006853 synchronized (sAudioPortGenerationLock) {
Eric Laurentf076db42015-01-14 13:23:27 -08006854 generation = sAudioPortGeneration;
6855 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006856 }
6857 return generation;
6858 }
6859
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006860 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6861 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006862 sAudioPortEventHandler.init();
Cole Faust7da659b2022-10-15 21:33:29 -07006863 synchronized (sAudioPortGenerationLock) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006864
Eric Laurentf076db42015-01-14 13:23:27 -08006865 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006866 int[] patchGeneration = new int[1];
6867 int[] portGeneration = new int[1];
6868 int status;
6869 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6870 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6871
6872 do {
6873 newPorts.clear();
6874 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006875 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006876 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006877 return status;
6878 }
6879 newPatches.clear();
6880 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006881 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006882 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006883 return status;
6884 }
jiabinc4ecaa52017-09-26 14:28:41 -07006885 // Loop until patch generation is the same as port generation unless audio ports
6886 // and audio patches are not null.
6887 } while (patchGeneration[0] != portGeneration[0]
6888 && (ports == null || patches == null));
6889 // If the patch generation doesn't equal port generation, return ERROR here in case
6890 // of mismatch between audio ports and audio patches.
6891 if (patchGeneration[0] != portGeneration[0]) {
6892 return ERROR;
6893 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006894
6895 for (int i = 0; i < newPatches.size(); i++) {
6896 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006897 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6898 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006899 newPatches.get(i).sources()[j] = portCfg;
6900 }
6901 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006902 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6903 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006904 newPatches.get(i).sinks()[j] = portCfg;
6905 }
6906 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006907 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6908 AudioPatch newPatch = i.next();
6909 boolean hasInvalidPort = false;
6910 for (AudioPortConfig portCfg : newPatch.sources()) {
6911 if (portCfg == null) {
6912 hasInvalidPort = true;
6913 break;
6914 }
6915 }
6916 for (AudioPortConfig portCfg : newPatch.sinks()) {
6917 if (portCfg == null) {
6918 hasInvalidPort = true;
6919 break;
6920 }
6921 }
6922 if (hasInvalidPort) {
6923 // Temporarily remove patches with invalid ports. One who created the patch
6924 // is responsible for dealing with the port change.
6925 i.remove();
6926 }
6927 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006928
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006929 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006930 sAudioPortsCached = newPorts;
6931 sAudioPatchesCached = newPatches;
6932 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006933 }
6934 if (ports != null) {
6935 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006936 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006937 }
6938 if (patches != null) {
6939 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006940 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006941 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006942 if (previousPorts != null) {
6943 previousPorts.clear();
6944 previousPorts.addAll(sPreviousAudioPortsCached);
6945 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006946 }
6947 return SUCCESS;
6948 }
6949
Eric Laurentf076db42015-01-14 13:23:27 -08006950 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006951 AudioPort port = portCfg.port();
6952 int k;
6953 for (k = 0; k < ports.size(); k++) {
6954 // compare handles because the port returned by JNI is not of the correct
6955 // subclass
6956 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006957 port = ports.get(k);
6958 break;
6959 }
6960 }
6961 if (k == ports.size()) {
Darwin Huangbb111732022-10-21 13:14:32 +00006962 // This can happen in case of stale audio patch referring to a removed device and is
6963 // handled by the caller.
Eric Laurentb69681c2014-05-19 19:02:51 -07006964 return null;
6965 }
6966 AudioGainConfig gainCfg = portCfg.gain();
6967 if (gainCfg != null) {
6968 AudioGain gain = port.gain(gainCfg.index());
6969 gainCfg = gain.buildConfig(gainCfg.mode(),
6970 gainCfg.channelMask(),
6971 gainCfg.values(),
6972 gainCfg.rampDurationMs());
6973 }
6974 return port.buildConfig(portCfg.samplingRate(),
6975 portCfg.channelMask(),
6976 portCfg.format(),
6977 gainCfg);
6978 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006979
6980 private OnAmPortUpdateListener mPortListener = null;
6981
6982 /**
6983 * The message sent to apps when the contents of the device list changes if they provide
Paul Wang9b2d0482022-05-17 10:18:01 +00006984 * a {@link Handler} object to {@link registerAudioDeviceCallback}.
Paul McLeane3383cc2015-05-08 11:41:20 -07006985 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006986 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6987 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6988 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006989
Paul McLean8e6c9f42015-05-19 11:13:41 -07006990 /**
6991 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6992 */
Jack He89f97982018-05-02 19:10:56 -07006993 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006994 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006995
6996 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006997 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6998 * the results list to only those device types they are interested in.
6999 */
7000 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07007001 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7002 * source (i.e. input) audio devices.
7003 */
7004 public static final int GET_DEVICES_INPUTS = 0x0001;
7005
7006 /**
7007 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7008 * sink (i.e. output) audio devices.
7009 */
7010 public static final int GET_DEVICES_OUTPUTS = 0x0002;
7011
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007012 /** @hide */
7013 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
7014 GET_DEVICES_INPUTS,
7015 GET_DEVICES_OUTPUTS }
7016 )
7017 @Retention(RetentionPolicy.SOURCE)
7018 public @interface AudioDeviceRole {}
7019
Paul McLeane3383cc2015-05-08 11:41:20 -07007020 /**
7021 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
7022 * source and sink devices.
7023 */
7024 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
7025
7026 /**
7027 * Determines if a given AudioDevicePort meets the specified filter criteria.
7028 * @param port The port to test.
7029 * @param flags A set of bitflags specifying the criteria to test.
7030 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
7031 **/
7032 private static boolean checkFlags(AudioDevicePort port, int flags) {
7033 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
7034 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
7035 }
7036
Paul McLean11354572015-08-07 12:50:48 -06007037 private static boolean checkTypes(AudioDevicePort port) {
7038 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07007039 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06007040 }
7041
Paul McLeane3383cc2015-05-08 11:41:20 -07007042 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007043 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
7044 * currently connected to the system and meeting the criteria specified in the
7045 * <code>flags</code> parameter.
jiabin83221092023-01-10 00:15:47 +00007046 * Notes that Android audio framework only support one device per device type. In that case,
7047 * if there are multiple audio device with the same device type connected to the Android device,
7048 * only the last reported device will be known by Android audio framework and returned by this
7049 * API.
Paul McLeane3383cc2015-05-08 11:41:20 -07007050 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007051 * @see #GET_DEVICES_OUTPUTS
7052 * @see #GET_DEVICES_INPUTS
7053 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07007054 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7055 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007056 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007057 return getDevicesStatic(flags);
7058 }
7059
Paul McLean8e6c9f42015-05-19 11:13:41 -07007060 /**
7061 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
7062 * objects from the current (internal) AudioDevicePort list.
7063 */
Paul McLean03346882015-05-12 15:36:56 -07007064 private static AudioDeviceInfo[]
7065 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007066
Paul McLean8e6c9f42015-05-19 11:13:41 -07007067 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07007068 int numRecs = 0;
7069 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007070 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007071 numRecs++;
7072 }
7073 }
7074
Paul McLean8e6c9f42015-05-19 11:13:41 -07007075 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07007076 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
7077 int slot = 0;
7078 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007079 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007080 deviceList[slot++] = new AudioDeviceInfo(port);
7081 }
7082 }
7083
7084 return deviceList;
7085 }
7086
Paul McLean03346882015-05-12 15:36:56 -07007087 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07007088 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
7089 * the add/remove callback mechanism to provide a list of the newly added or removed devices
7090 * rather than the whole list and make the app figure it out.
7091 * Note that calling this method with:
7092 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
7093 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07007094 */
7095 private static AudioDeviceInfo[] calcListDeltas(
7096 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
7097
7098 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
7099
7100 AudioDevicePort cur_port = null;
7101 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
7102 boolean cur_port_found = false;
7103 cur_port = ports_B.get(cur_index);
7104 for (int prev_index = 0;
7105 prev_index < ports_A.size() && !cur_port_found;
7106 prev_index++) {
7107 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
7108 }
7109
7110 if (!cur_port_found) {
7111 delta_ports.add(cur_port);
7112 }
7113 }
7114
7115 return infoListFromPortList(delta_ports, flags);
7116 }
7117
Paul McLeane3383cc2015-05-08 11:41:20 -07007118 /**
Paul McLean03346882015-05-12 15:36:56 -07007119 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
7120 * connected to the system and meeting the criteria specified in the <code>flags</code>
7121 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007122 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07007123 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007124 * @see #GET_DEVICES_OUTPUTS
7125 * @see #GET_DEVICES_INPUTS
7126 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07007127 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7128 * @hide
7129 */
7130 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
7131 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
7132 int status = AudioManager.listAudioDevicePorts(ports);
7133 if (status != AudioManager.SUCCESS) {
7134 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07007135 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07007136 }
7137
7138 return infoListFromPortList(ports, flags);
7139 }
7140
7141 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007142 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
7143 * @param portId The audio port ID to look up for.
7144 * @param flags A set of bitflags specifying the criteria to test.
7145 * @see #GET_DEVICES_OUTPUTS
7146 * @see #GET_DEVICES_INPUTS
7147 * @see #GET_DEVICES_ALL
7148 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
7149 * @hide
7150 */
7151 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
7152 if (portId == 0) {
7153 return null;
7154 }
7155 AudioDeviceInfo[] devices = getDevicesStatic(flags);
7156 for (AudioDeviceInfo device : devices) {
7157 if (device.getId() == portId) {
7158 return device;
7159 }
7160 }
7161 return null;
7162 }
7163
7164 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007165 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07007166 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007167 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
7168 * notifications.
7169 * @param handler Specifies the {@link Handler} object for the thread on which to execute
7170 * the callback. If <code>null</code>, the {@link Handler} associated with the main
7171 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07007172 */
Paul McLean03346882015-05-12 15:36:56 -07007173 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08007174 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07007175 synchronized (mDeviceCallbacks) {
7176 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007177 if (mDeviceCallbacks.size() == 0) {
7178 if (mPortListener == null) {
7179 mPortListener = new OnAmPortUpdateListener();
7180 }
7181 registerAudioPortUpdateListener(mPortListener);
7182 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007183 NativeEventHandlerDelegate delegate =
7184 new NativeEventHandlerDelegate(callback, handler);
7185 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07007186 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07007187 }
7188 }
7189 }
7190
7191 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007192 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07007193 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007194 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08007195 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07007196 */
Paul McLean03346882015-05-12 15:36:56 -07007197 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
7198 synchronized (mDeviceCallbacks) {
7199 if (mDeviceCallbacks.containsKey(callback)) {
7200 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07007201 if (mDeviceCallbacks.size() == 0) {
7202 unregisterAudioPortUpdateListener(mPortListener);
7203 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007204 }
7205 }
7206 }
7207
jiabinc0f49442018-01-05 10:23:50 -08007208 /**
7209 * Set port id for microphones by matching device type and address.
7210 * @hide
7211 */
7212 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
7213 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
7214 for (int i = microphones.size() - 1; i >= 0; i--) {
7215 boolean foundPortId = false;
7216 for (AudioDeviceInfo device : devices) {
7217 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
7218 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
7219 microphones.get(i).setId(device.getId());
7220 foundPortId = true;
7221 break;
7222 }
7223 }
7224 if (!foundPortId) {
7225 Log.i(TAG, "Failed to find port id for device with type:"
7226 + microphones.get(i).getType() + " address:"
7227 + microphones.get(i).getAddress());
7228 microphones.remove(i);
7229 }
7230 }
7231 }
7232
7233 /**
jiabin589a2362018-02-22 16:21:53 -08007234 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
7235 * @hide
7236 */
7237 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
7238 int deviceType = deviceInfo.getType();
7239 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
7240 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
7241 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
7242 : MicrophoneInfo.LOCATION_PERIPHERAL;
7243 MicrophoneInfo microphone = new MicrophoneInfo(
7244 deviceInfo.getPort().name() + deviceInfo.getId(),
7245 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
7246 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
7247 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
7248 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
7249 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
7250 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
7251 microphone.setId(deviceInfo.getId());
7252 return microphone;
7253 }
7254
7255 /**
jiabind0be5b22018-04-10 14:10:04 -07007256 * Add {@link MicrophoneInfo} by device information while filtering certain types.
7257 */
7258 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
7259 HashSet<Integer> filterTypes) {
7260 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
7261 for (AudioDeviceInfo device : devices) {
7262 if (filterTypes.contains(device.getType())) {
7263 continue;
7264 }
7265 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
7266 microphones.add(microphone);
7267 }
7268 }
7269
7270 /**
jiabinc0f49442018-01-05 10:23:50 -08007271 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
7272 * of all available microphones. The list is empty when no microphones are available
7273 * on the device. An error during the query will result in an IOException being thrown.
7274 *
7275 * @return a list that contains all microphones' characteristics
7276 * @throws IOException if an error occurs.
7277 */
7278 public List<MicrophoneInfo> getMicrophones() throws IOException {
7279 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
7280 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07007281 HashSet<Integer> filterTypes = new HashSet<>();
7282 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08007283 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07007284 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07007285 if (status != AudioManager.ERROR_INVALID_OPERATION) {
7286 Log.e(TAG, "getMicrophones failed:" + status);
7287 }
7288 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07007289 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
7290 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08007291 }
7292 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07007293 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
7294 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08007295 return microphones;
7296 }
7297
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007298 /**
7299 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01007300 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007301 *
7302 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01007303 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007304 * @hide
7305 */
William Escandea05cb452021-12-08 14:14:19 +01007306 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7307 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
7308 ArrayList<Integer> formatsList = new ArrayList<>();
7309 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007310
William Escandea05cb452021-12-08 14:14:19 +01007311 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
7312 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007313 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01007314 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
7315 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007316 }
7317
William Escandea05cb452021-12-08 14:14:19 +01007318 for (Integer format : formatsList) {
7319 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
7320 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
Etienne Ruffieux2c5180a2022-03-08 13:31:41 +00007321 codecConfigList.add(
7322 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007323 }
William Escandea05cb452021-12-08 14:14:19 +01007324 }
7325 return codecConfigList;
7326 }
7327
7328 /**
7329 * Returns a list of audio formats that corresponds to encoding formats
7330 * supported on offload path for Le audio playback.
7331 *
7332 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
7333 * supported for offload Le Audio playback
7334 * @hide
7335 */
7336 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7337 @NonNull
7338 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
7339 ArrayList<Integer> formatsList = new ArrayList<>();
7340 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
7341
7342 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
7343 AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
7344 if (status != AudioManager.SUCCESS) {
7345 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08007346 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007347 }
William Escandea05cb452021-12-08 14:14:19 +01007348
7349 for (Integer format : formatsList) {
7350 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
7351 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
7352 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
7353 .setCodecType(btLeAudioCodec)
7354 .build());
7355 }
7356 }
7357 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007358 }
7359
Paul McLeancbeb8a22015-06-10 08:21:27 -07007360 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
7361 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
7362 // of the ports that exist at the time of the last notification.
7363 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
7364
Paul McLeane3383cc2015-05-08 11:41:20 -07007365 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007366 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07007367 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07007368 */
jiabin8c3a7672018-05-22 15:44:21 -07007369 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07007370 int status;
7371
Paul McLeancbeb8a22015-06-10 08:21:27 -07007372 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07007373 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
7374 status = AudioManager.listAudioDevicePorts(current_ports);
7375 if (status != AudioManager.SUCCESS) {
7376 return;
7377 }
7378
Paul McLeancbeb8a22015-06-10 08:21:27 -07007379 if (handler != null) {
7380 // This is the callback for the registration, so send the current list
7381 AudioDeviceInfo[] deviceList =
7382 infoListFromPortList(current_ports, GET_DEVICES_ALL);
7383 handler.sendMessage(
7384 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
7385 } else {
7386 AudioDeviceInfo[] added_devices =
7387 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
7388 AudioDeviceInfo[] removed_devices =
7389 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07007390 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07007391 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
7392 handler = mDeviceCallbacks.valueAt(i).getHandler();
7393 if (handler != null) {
7394 if (removed_devices.length != 0) {
7395 handler.sendMessage(Message.obtain(handler,
7396 MSG_DEVICES_DEVICES_REMOVED,
7397 removed_devices));
7398 }
7399 if (added_devices.length != 0) {
7400 handler.sendMessage(Message.obtain(handler,
7401 MSG_DEVICES_DEVICES_ADDED,
7402 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07007403 }
Paul McLean03346882015-05-12 15:36:56 -07007404 }
7405 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007406 }
7407 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007408
7409 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07007410 }
7411
7412 /**
7413 * Handles Port list update notifications from the AudioManager
7414 */
7415 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
7416 static final String TAG = "OnAmPortUpdateListener";
7417 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07007418 synchronized (mDeviceCallbacks) {
7419 broadcastDeviceListChange_sync(null);
7420 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007421 }
7422
7423 /**
7424 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007425 * Note: We don't do anything with Patches at this time, so ignore this notification.
7426 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07007427 */
7428 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
7429
7430 /**
7431 * Callback method called when the mediaserver dies
7432 */
7433 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07007434 synchronized (mDeviceCallbacks) {
7435 broadcastDeviceListChange_sync(null);
7436 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007437 }
7438 }
7439
Eric Laurent1d3cdce2018-01-20 10:31:21 -08007440
7441 /**
7442 * @hide
7443 * Abstract class to receive event notification about audioserver process state.
7444 */
7445 @SystemApi
7446 public abstract static class AudioServerStateCallback {
7447 public void onAudioServerDown() { }
7448 public void onAudioServerUp() { }
7449 }
7450
7451 private Executor mAudioServerStateExec;
7452 private AudioServerStateCallback mAudioServerStateCb;
7453 private final Object mAudioServerStateCbLock = new Object();
7454
7455 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
7456 new IAudioServerStateDispatcher.Stub() {
7457 @Override
7458 public void dispatchAudioServerStateChange(boolean state) {
7459 Executor exec;
7460 AudioServerStateCallback cb;
7461
7462 synchronized (mAudioServerStateCbLock) {
7463 exec = mAudioServerStateExec;
7464 cb = mAudioServerStateCb;
7465 }
7466
7467 if ((exec == null) || (cb == null)) {
7468 return;
7469 }
7470 if (state) {
7471 exec.execute(() -> cb.onAudioServerUp());
7472 } else {
7473 exec.execute(() -> cb.onAudioServerDown());
7474 }
7475 }
7476 };
7477
7478 /**
7479 * @hide
7480 * Registers a callback for notification of audio server state changes.
7481 * @param executor {@link Executor} to handle the callbacks
7482 * @param stateCallback the callback to receive the audio server state changes
7483 * To remove the callabck, pass a null reference for both executor and stateCallback.
7484 */
7485 @SystemApi
7486 public void setAudioServerStateCallback(@NonNull Executor executor,
7487 @NonNull AudioServerStateCallback stateCallback) {
7488 if (stateCallback == null) {
7489 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
7490 }
7491 if (executor == null) {
7492 throw new IllegalArgumentException(
7493 "Illegal null Executor for the AudioServerStateCallback");
7494 }
7495
7496 synchronized (mAudioServerStateCbLock) {
7497 if (mAudioServerStateCb != null) {
7498 throw new IllegalStateException(
7499 "setAudioServerStateCallback called with already registered callabck");
7500 }
7501 final IAudioService service = getService();
7502 try {
7503 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7504 } catch (RemoteException e) {
7505 throw e.rethrowFromSystemServer();
7506 }
7507 mAudioServerStateExec = executor;
7508 mAudioServerStateCb = stateCallback;
7509 }
7510 }
7511
7512 /**
7513 * @hide
7514 * Unregisters the callback for notification of audio server state changes.
7515 */
7516 @SystemApi
7517 public void clearAudioServerStateCallback() {
7518 synchronized (mAudioServerStateCbLock) {
7519 if (mAudioServerStateCb != null) {
7520 final IAudioService service = getService();
7521 try {
7522 service.unregisterAudioServerStateDispatcher(
7523 mAudioServerStateDispatcher);
7524 } catch (RemoteException e) {
7525 throw e.rethrowFromSystemServer();
7526 }
7527 }
7528 mAudioServerStateExec = null;
7529 mAudioServerStateCb = null;
7530 }
7531 }
7532
7533 /**
7534 * @hide
7535 * Checks if native audioservice is running or not.
7536 * @return true if native audioservice runs, false otherwise.
7537 */
7538 @SystemApi
7539 public boolean isAudioServerRunning() {
7540 final IAudioService service = getService();
7541 try {
7542 return service.isAudioServerRunning();
7543 } catch (RemoteException e) {
7544 throw e.rethrowFromSystemServer();
7545 }
7546 }
7547
jiabin39940752018-04-02 18:18:45 -07007548 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007549 * Sets the surround sound mode.
7550 *
7551 * @return true if successful, otherwise false
7552 */
7553 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
7554 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7555 try {
7556 return getService().setEncodedSurroundMode(mode);
7557 } catch (RemoteException e) {
7558 throw e.rethrowFromSystemServer();
7559 }
7560 }
7561
7562 /**
7563 * Gets the surround sound mode.
7564 *
7565 * @return true if successful, otherwise false
7566 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007567 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7568 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007569 return getService().getEncodedSurroundMode(
7570 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007571 } catch (RemoteException e) {
7572 throw e.rethrowFromSystemServer();
7573 }
7574 }
7575
7576 /**
jiabin39940752018-04-02 18:18:45 -07007577 * @hide
7578 * Returns all surround formats.
7579 * @return a map where the key is a surround format and
7580 * the value indicates the surround format is enabled or not
7581 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007582 @TestApi
7583 @NonNull
jiabin39940752018-04-02 18:18:45 -07007584 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007585 try {
7586 return getService().getSurroundFormats();
7587 } catch (RemoteException e) {
7588 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007589 }
jiabin39940752018-04-02 18:18:45 -07007590 }
7591
7592 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007593 * Sets and persists a certain surround format as enabled or not.
7594 * <p>
7595 * This API is called by TvSettings surround sound menu when user enables or disables a
7596 * surround sound format. This setting is persisted as global user setting.
7597 * Applications should revert their changes to surround sound settings unless they intend to
7598 * modify the global user settings across all apps. The framework does not auto-revert an
7599 * application's settings after a lifecycle event. Audio focus is not required to apply these
7600 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007601 *
jiabin39940752018-04-02 18:18:45 -07007602 * @param enabled the required surround format state, true for enabled, false for disabled
7603 * @return true if successful, otherwise false
7604 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007605 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007606 public boolean setSurroundFormatEnabled(
7607 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007608 try {
7609 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7610 } catch (RemoteException e) {
7611 throw e.rethrowFromSystemServer();
7612 }
7613 }
7614
7615 /**
7616 * Gets whether a certain surround format is enabled or not.
7617 * @param audioFormat a surround format
7618 *
7619 * @return whether the required surround format is enabled
7620 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007621 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7622 try {
7623 return getService().isSurroundFormatEnabled(audioFormat);
7624 } catch (RemoteException e) {
7625 throw e.rethrowFromSystemServer();
7626 }
jiabin39940752018-04-02 18:18:45 -07007627 }
7628
7629 /**
7630 * @hide
7631 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007632 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007633 *
Kriti Dang01924232021-03-02 13:51:09 +01007634 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007635 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007636 @TestApi
7637 @NonNull
7638 public List<Integer> getReportedSurroundFormats() {
7639 try {
7640 return getService().getReportedSurroundFormats();
7641 } catch (RemoteException e) {
7642 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007643 }
jiabin39940752018-04-02 18:18:45 -07007644 }
7645
jiabin66f9e722018-11-02 16:20:19 -07007646 /**
7647 * Return if audio haptic coupled playback is supported or not.
7648 *
7649 * @return whether audio haptic playback supported.
7650 */
7651 public static boolean isHapticPlaybackSupported() {
7652 return AudioSystem.isHapticPlaybackSupported();
7653 }
7654
François Gaffie0699fec2018-07-09 14:35:10 +02007655 /**
7656 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08007657 * Indicates whether a platform supports the Ultrasound feature which covers the playback
7658 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
7659 * usage will be
7660 * To start the Ultrasound playback:
7661 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
7662 * To start the Ultrasound capture:
7663 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
7664 *
7665 * @return whether the ultrasound feature is supported, true when platform supports both
7666 * Ultrasound playback and capture, false otherwise.
7667 */
7668 @SystemApi
Carter Hsu3ea30de42022-02-15 15:59:00 +08007669 @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
7670 public boolean isUltrasoundSupported() {
7671 try {
7672 return getService().isUltrasoundSupported();
7673 } catch (RemoteException e) {
7674 throw e.rethrowFromSystemServer();
7675 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08007676 }
7677
7678 /**
7679 * @hide
Atneya Naireeab0a72022-12-15 09:32:51 -08007680 * Indicates whether the platform supports capturing content from the hotword recognition
7681 * pipeline. To capture content of this type, create an AudioRecord with
7682 * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}.
7683 * @param lookbackAudio Query if the hotword stream additionally supports providing buffered
7684 * audio prior to stream open.
7685 * @return True if the platform supports capturing hotword content, and if lookbackAudio
7686 * is true, if it additionally supports capturing buffered hotword content prior to stream
7687 * open. False otherwise.
7688 */
7689 @SystemApi
7690 @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
7691 public boolean isHotwordStreamSupported(boolean lookbackAudio) {
7692 try {
7693 return getService().isHotwordStreamSupported(lookbackAudio);
7694 } catch (RemoteException e) {
7695 return false;
7696 }
7697 }
7698
7699 /**
7700 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02007701 * Introspection API to retrieve audio product strategies.
7702 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7703 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7704 * by OEM without any needs of AOSP patches.
7705 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7706 * strategy refered either by its index or human readable string. It will allow clients
7707 * application to start streaming data using these {@link AudioAttributes} on the selected
7708 * device by Audio Policy Engine.
7709 * @return a (possibly zero-length) array of
7710 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7711 */
7712 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007713 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007714 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007715 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007716 final IAudioService service = getService();
7717 try {
7718 return service.getAudioProductStrategies();
7719 } catch (RemoteException e) {
7720 throw e.rethrowFromSystemServer();
7721 }
7722 }
7723
François Gaffieadcd00a2018-09-18 17:06:26 +02007724 /**
7725 * @hide
7726 * Introspection API to retrieve audio volume groups.
7727 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7728 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007729 * @return a (possibly zero-length) List of
7730 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007731 */
7732 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007733 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007734 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007735 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007736 final IAudioService service = getService();
7737 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007738 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007739 } catch (RemoteException e) {
7740 throw e.rethrowFromSystemServer();
7741 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007742 }
7743
7744 /**
7745 * @hide
7746 * Callback registered by client to be notified upon volume group change.
7747 */
7748 @SystemApi
7749 public abstract static class VolumeGroupCallback {
7750 /**
7751 * Callback method called upon audio volume group change.
7752 * @param group the group for which the volume has changed
7753 */
7754 public void onAudioVolumeGroupChanged(int group, int flags) {}
7755 }
7756
7757 /**
7758 * @hide
7759 * Register an audio volume group change listener.
7760 * @param callback the {@link VolumeGroupCallback} to register
7761 */
7762 @SystemApi
7763 public void registerVolumeGroupCallback(
7764 @NonNull Executor executor,
7765 @NonNull VolumeGroupCallback callback) {
7766 Preconditions.checkNotNull(executor, "executor must not be null");
7767 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7768 sAudioAudioVolumeGroupChangedHandler.init();
7769 // TODO: make use of executor
7770 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7771 }
7772
7773 /**
7774 * @hide
7775 * Unregister an audio volume group change listener.
7776 * @param callback the {@link VolumeGroupCallback} to unregister
7777 */
7778 @SystemApi
7779 public void unregisterVolumeGroupCallback(
7780 @NonNull VolumeGroupCallback callback) {
7781 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7782 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7783 }
jiabin39940752018-04-02 18:18:45 -07007784
jiabinad225202019-03-20 15:22:50 -07007785 /**
7786 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007787 *
7788 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007789 * @param uri the {@link Uri} of the asset.
7790 * @return true if the assert contains haptic channels.
7791 * @hide
7792 */
jiabincfcf1032021-07-01 16:30:50 -07007793 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7794 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007795 try {
jiabincfcf1032021-07-01 16:30:50 -07007796 extractor.setDataSource(context, uri, null);
7797 for (int i = 0; i < extractor.getTrackCount(); i++) {
7798 MediaFormat format = extractor.getTrackFormat(i);
7799 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7800 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7801 return true;
7802 }
7803 }
7804 } catch (IOException e) {
7805 Log.e(TAG, "hasHapticChannels failure:" + e);
7806 }
7807 return false;
7808 }
7809
7810 /**
7811 * Return if an asset contains haptic channels or not.
7812 *
7813 * @param context the {@link Context} to resolve the uri.
7814 * @param uri the {@link Uri} of the asset.
7815 * @return true if the assert contains haptic channels.
7816 * @hide
7817 */
7818 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7819 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07007820
jiabincfcf1032021-07-01 16:30:50 -07007821 if (context != null) {
7822 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07007823 }
7824
7825 Context cachedContext = sContext.get();
7826 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07007827 if (DEBUG) {
7828 Log.d(TAG, "Try to use static context to query if having haptic channels");
7829 }
jiabin0f3339c2021-07-09 11:50:07 -07007830 return hasHapticChannelsImpl(cachedContext, uri);
7831 }
7832
7833 // Try with audio service context, this may fail to get correct result.
7834 if (DEBUG) {
7835 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7836 }
7837 try {
7838 return getService().hasHapticChannels(uri);
7839 } catch (RemoteException e) {
7840 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07007841 }
7842 }
7843
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007844 /**
7845 * Set whether or not there is an active RTT call.
7846 * This method should be called by Telecom service.
7847 * @hide
7848 * TODO: make this a @SystemApi
7849 */
7850 public static void setRttEnabled(boolean rttEnabled) {
7851 try {
7852 getService().setRttEnabled(rttEnabled);
7853 } catch (RemoteException e) {
7854 throw e.rethrowFromSystemServer();
7855 }
7856 }
7857
Jin Seok Park16aeba382020-08-06 12:52:54 +09007858 /**
7859 * Adjusts the volume of the most relevant stream, or the given fallback
7860 * stream.
7861 * <p>
7862 * This method should only be used by applications that replace the
7863 * platform-wide management of audio settings or the main telephony
7864 * application.
7865 * <p>
7866 * This method has no effect if the device implements a fixed volume policy
7867 * as indicated by {@link #isVolumeFixed()}.
7868 * <p>This API checks if the caller has the necessary permissions based on the provided
7869 * component name, uid, and pid values.
7870 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7871 *
7872 * @param suggestedStreamType The stream type that will be used if there
7873 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7874 * valid here.
7875 * @param direction The direction to adjust the volume. One of
7876 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7877 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7878 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7879 * @param flags One or more flags.
7880 * @param packageName the package name of client application
7881 * @param uid the uid of client application
7882 * @param pid the pid of client application
7883 * @param targetSdkVersion the target sdk version of client application
7884 * @see #adjustVolume(int, int)
7885 * @see #adjustStreamVolume(int, int, int)
7886 * @see #setStreamVolume(int, int, int)
7887 * @see #isVolumeFixed()
7888 *
7889 * @hide
7890 */
7891 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7892 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7893 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7894 try {
7895 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7896 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7897 } catch (RemoteException e) {
7898 throw e.rethrowFromSystemServer();
7899 }
7900 }
7901
7902 /**
7903 * Adjusts the volume of a particular stream by one step in a direction.
7904 * <p>
7905 * This method should only be used by applications that replace the platform-wide
7906 * management of audio settings or the main telephony application.
7907 * <p>This method has no effect if the device implements a fixed volume policy
7908 * as indicated by {@link #isVolumeFixed()}.
7909 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7910 * unless the app has been granted Do Not Disturb Access.
7911 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7912 * <p>This API checks if the caller has the necessary permissions based on the provided
7913 * component name, uid, and pid values.
7914 * See {@link #adjustStreamVolume(int, int, int)}.
7915 *
7916 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7917 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7918 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7919 * @param direction The direction to adjust the volume. One of
7920 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7921 * {@link #ADJUST_SAME}.
7922 * @param flags One or more flags.
7923 * @param packageName the package name of client application
7924 * @param uid the uid of client application
7925 * @param pid the pid of client application
7926 * @param targetSdkVersion the target sdk version of client application
7927 * @see #adjustVolume(int, int)
7928 * @see #setStreamVolume(int, int, int)
7929 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7930 * and the caller is not granted notification policy access.
7931 *
7932 * @hide
7933 */
7934 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7935 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7936 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7937 try {
7938 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7939 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7940 } catch (RemoteException e) {
7941 throw e.rethrowFromSystemServer();
7942 }
7943 }
7944
7945 /**
7946 * Sets the volume index for a particular stream.
7947 * <p>This method has no effect if the device implements a fixed volume policy
7948 * as indicated by {@link #isVolumeFixed()}.
7949 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7950 * the app has been granted Do Not Disturb Access.
7951 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7952 * <p>This API checks if the caller has the necessary permissions based on the provided
7953 * component name, uid, and pid values.
7954 * See {@link #setStreamVolume(int, int, int)}.
7955 *
7956 * @param streamType The stream whose volume index should be set.
7957 * @param index The volume index to set. See
7958 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7959 * @param flags One or more flags.
7960 * @param packageName the package name of client application
7961 * @param uid the uid of client application
7962 * @param pid the pid of client application
7963 * @param targetSdkVersion the target sdk version of client application
7964 * @see #getStreamMaxVolume(int)
7965 * @see #getStreamVolume(int)
7966 * @see #isVolumeFixed()
7967 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7968 * and the caller is not granted notification policy access.
7969 *
7970 * @hide
7971 */
7972 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7973 public void setStreamVolumeForUid(int streamType, int index, int flags,
7974 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7975 try {
7976 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7977 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7978 } catch (RemoteException e) {
7979 throw e.rethrowFromSystemServer();
7980 }
7981 }
7982
7983
hjin81.lee4e984e52019-12-05 14:34:52 +09007984 /** @hide
7985 * TODO: make this a @SystemApi */
7986 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7987 public void setMultiAudioFocusEnabled(boolean enabled) {
7988 try {
7989 getService().setMultiAudioFocusEnabled(enabled);
7990 } catch (RemoteException e) {
7991 throw e.rethrowFromSystemServer();
7992 }
7993 }
7994
Eric Laurent43a78de2020-07-24 17:11:15 -07007995
7996 /**
7997 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7998 * For more details on Hardware A/V synchronization please refer to
7999 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
8000 * media tunneling documentation</a>.
8001 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
8002 * @return the HW A/V sync ID for this audio session (an integer different from 0).
8003 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
8004 */
8005 public int getAudioHwSyncForSession(int sessionId) {
8006 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
8007 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
8008 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
8009 }
8010 return hwSyncId;
8011 }
8012
Eric Laurentb36d4a12020-10-09 09:52:49 -07008013 /**
8014 * Selects the audio device that should be used for communication use cases, for instance voice
8015 * or video calls. This method can be used by voice or video chat applications to select a
8016 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01008017 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
Eric Laurent6aa23612022-11-18 16:08:20 +01008018 * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role
8019 * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching
8020 * source device is selected automatically by the platform.
8021 * <p>The selection is active as long as the requesting application process lives, until
Eric Laurent7412f572021-02-11 15:10:31 +01008022 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008023 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01008024 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008025 * <p>In case of simultaneous requests by multiple applications the priority is given to the
8026 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
8027 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
8028 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
8029 * telephony application with permission
8030 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
8031 * <p> If the requested devices is not currently available, the request will be rejected and
8032 * the method will return false.
8033 * <p>This API replaces the following deprecated APIs:
8034 * <ul>
8035 * <li> {@link #startBluetoothSco()}
8036 * <li> {@link #stopBluetoothSco()}
8037 * <li> {@link #setSpeakerphoneOn(boolean)}
8038 * </ul>
8039 * <h4>Example</h4>
8040 * <p>The example below shows how to enable and disable speakerphone mode.
8041 * <pre class="prettyprint">
8042 * // Get an AudioManager instance
8043 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01008044 * AudioDeviceInfo speakerDevice = null;
8045 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
8046 * for (AudioDeviceInfo device : devices) {
8047 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
8048 * speakerDevice = device;
8049 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008050 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008051 * }
8052 * if (speakerDevice != null) {
8053 * // Turn speakerphone ON.
8054 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
8055 * if (!result) {
8056 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008057 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008058 * // Turn speakerphone OFF.
8059 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008060 * }
8061 * </pre>
8062 * @param device the requested audio device.
8063 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
8064 * @throws IllegalArgumentException If an invalid device is specified.
8065 */
Eric Laurent7412f572021-02-11 15:10:31 +01008066 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008067 Objects.requireNonNull(device);
8068 try {
8069 if (device.getId() == 0) {
8070 throw new IllegalArgumentException("In valid device: " + device);
8071 }
Eric Laurent7412f572021-02-11 15:10:31 +01008072 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008073 } catch (RemoteException e) {
8074 throw e.rethrowFromSystemServer();
8075 }
8076 }
8077
8078 /**
8079 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01008080 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008081 */
Eric Laurent7412f572021-02-11 15:10:31 +01008082 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008083 try {
Eric Laurent7412f572021-02-11 15:10:31 +01008084 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07008085 } catch (RemoteException e) {
8086 throw e.rethrowFromSystemServer();
8087 }
8088 }
8089
8090 /**
8091 * Returns currently selected audio device for communication.
8092 * <p>This API replaces the following deprecated APIs:
8093 * <ul>
8094 * <li> {@link #isBluetoothScoOn()}
8095 * <li> {@link #isSpeakerphoneOn()}
8096 * </ul>
8097 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01008098 * currently selected for communication use cases. Can be null on platforms
8099 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008100 * is used.
8101 */
8102 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01008103 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008104 try {
8105 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01008106 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
8107 } catch (RemoteException e) {
8108 throw e.rethrowFromSystemServer();
8109 }
8110 }
8111
8112 /**
8113 * Returns a list of audio devices that can be selected for communication use cases via
8114 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
8115 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
8116 */
8117 @NonNull
8118 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
8119 try {
8120 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
8121 int[] portIds = getService().getAvailableCommunicationDeviceIds();
8122 for (int portId : portIds) {
8123 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
8124 if (device == null) {
8125 continue;
8126 }
8127 devices.add(device);
8128 }
8129 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008130 } catch (RemoteException e) {
8131 throw e.rethrowFromSystemServer();
8132 }
8133 }
8134
8135 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01008136 * Returns a list of direct {@link AudioProfile} that are supported for the specified
8137 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
8138 * is possible.
8139 *
8140 * <p>Direct playback means that the audio stream is not resampled or downmixed
8141 * by the framework. Checking for direct support can help the app select the representation
8142 * of audio content that most closely matches the capabilities of the device and peripherals
8143 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
8144 * or mixed with other streams, if needed.
8145 * <p>When using this information to inform your application which audio format to play,
8146 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
8147 * @param attributes a non-null {@link AudioAttributes} instance.
8148 * @return a list of {@link AudioProfile}
8149 */
8150 @NonNull
8151 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
8152 Objects.requireNonNull(attributes);
8153 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
8154 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
8155 if (status != SUCCESS) {
8156 Log.w(TAG, "getDirectProfilesForAttributes failed.");
8157 return new ArrayList<>();
8158 }
8159 return audioProfilesList;
8160 }
8161
8162 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008163 * @hide
8164 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
8165 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
8166 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
8167 * The method will return null if no device of the provided type is connected.
8168 * If more than one device of the provided type is connected, an object corresponding to the
8169 * first device encountered in the enumeration list will be returned.
8170 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01008171 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008172 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
8173 * @throws IllegalArgumentException If an invalid device type is specified.
8174 */
8175 @TestApi
8176 @Nullable
8177 public static AudioDeviceInfo getDeviceInfoFromType(
8178 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01008179 return getDeviceInfoFromTypeAndAddress(deviceType, null);
8180 }
8181
Eric Laurent78eef3a2021-11-09 16:10:42 +01008182 /**
Eric Laurent7412f572021-02-11 15:10:31 +01008183 * @hide
8184 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
8185 * address provided.
8186 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
8187 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
8188 * If a null address is provided, the matching will happen on the type only.
8189 * The method will return null if no device of the provided type and address is connected.
8190 * If more than one device of the provided type is connected, an object corresponding to the
8191 * first device encountered in the enumeration list will be returned.
8192 * @param type The device device for which an <code>AudioDeviceInfo</code>
8193 * object is queried.
8194 * @param address The device address for which an <code>AudioDeviceInfo</code>
8195 * object is queried or null if requesting match on type only.
8196 * @return An AudioDeviceInfo object or null if no matching device is connected.
8197 * @throws IllegalArgumentException If an invalid device type is specified.
8198 */
8199 @Nullable
8200 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
8201 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008202 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01008203 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008204 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01008205 if (device.getType() == type) {
8206 deviceForType = device;
8207 if (address == null || address.equals(device.getAddress())) {
8208 return device;
8209 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008210 }
8211 }
Eric Laurent7412f572021-02-11 15:10:31 +01008212 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008213 }
8214
8215 /**
8216 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01008217 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008218 */
8219 public interface OnCommunicationDeviceChangedListener {
8220 /**
8221 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01008222 * @param device the audio device requested for communication use cases.
8223 * Can be null on platforms not supporting
8224 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008225 */
8226 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
8227 }
8228
8229 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008230 * manages the OnCommunicationDeviceChangedListener listeners and the
8231 * CommunicationDeviceDispatcherStub
8232 */
8233 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
8234 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
8235 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008236 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01008237 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008238 * @param executor
8239 * @param listener
8240 */
8241 public void addOnCommunicationDeviceChangedListener(
8242 @NonNull @CallbackExecutor Executor executor,
8243 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008244 mCommDeviceChangedListenerMgr.addListener(
8245 executor, listener, "addOnCommunicationDeviceChangedListener",
8246 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008247 }
8248
8249 /**
8250 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01008251 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008252 * @param listener
8253 */
8254 public void removeOnCommunicationDeviceChangedListener(
8255 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008256 mCommDeviceChangedListenerMgr.removeListener(listener,
8257 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07008258 }
8259
Eric Laurentb36d4a12020-10-09 09:52:49 -07008260 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008261 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008262
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008263 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008264 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008265 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008266 if (register) {
8267 getService().registerCommunicationDeviceDispatcher(this);
8268 } else {
8269 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07008270 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008271 } catch (RemoteException e) {
8272 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008273 }
8274 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008275
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008276 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008277 public void dispatchCommunicationDeviceChanged(int portId) {
8278 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008279 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008280 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07008281 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008282 }
8283
Eric Laurent78eef3a2021-11-09 16:10:42 +01008284
8285 /**
8286 * @hide
8287 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
8288 * PSTN call.
8289 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
8290 * an AudioTrack for call uplink audio injection and
8291 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
8292 * an AudioRecord for call downlink audio extraction.
8293 * @return true if PSTN call audio is accessible, false otherwise.
8294 */
8295 @TestApi
8296 @SystemApi
8297 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8298 public boolean isPstnCallAudioInterceptable() {
8299 final IAudioService service = getService();
8300 try {
8301 return service.isPstnCallAudioInterceptable();
8302 } catch (RemoteException e) {
8303 throw e.rethrowFromSystemServer();
8304 }
8305 }
8306
8307 /** @hide */
8308 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
8309 CALL_REDIRECT_NONE,
8310 CALL_REDIRECT_PSTN,
8311 CALL_REDIRECT_VOIP }
8312 )
8313 @Retention(RetentionPolicy.SOURCE)
8314 public @interface CallRedirectionMode {}
8315
8316 /**
8317 * Not used for call redirection
8318 * @hide
8319 */
8320 public static final int CALL_REDIRECT_NONE = 0;
8321 /**
8322 * Used to redirect PSTN call
8323 * @hide
8324 */
8325 public static final int CALL_REDIRECT_PSTN = 1;
8326 /**
8327 * Used to redirect VoIP call
8328 * @hide
8329 */
8330 public static final int CALL_REDIRECT_VOIP = 2;
8331
8332
8333 private @CallRedirectionMode int getCallRedirectMode() {
8334 int mode = getMode();
8335 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
8336 || mode == MODE_CALL_REDIRECT) {
8337 return CALL_REDIRECT_PSTN;
8338 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
8339 return CALL_REDIRECT_VOIP;
8340 }
8341 return CALL_REDIRECT_NONE;
8342 }
8343
8344 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
8345 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
8346 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
8347 throw new UnsupportedOperationException(" Unsupported encoding ");
8348 }
8349 if (format.getSampleRate() < 8000
8350 || format.getSampleRate() > 48000) {
8351 throw new UnsupportedOperationException(" Unsupported sample rate ");
8352 }
8353 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
8354 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
8355 throw new UnsupportedOperationException(" Unsupported output channel mask ");
8356 }
8357 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
8358 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
8359 throw new UnsupportedOperationException(" Unsupported input channel mask ");
8360 }
8361 }
8362
8363 class CallIRedirectionClientInfo {
8364 public WeakReference trackOrRecord;
8365 public int redirectMode;
8366 }
8367
8368 private Object mCallRedirectionLock = new Object();
8369 @GuardedBy("mCallRedirectionLock")
8370 private CallInjectionModeChangedListener mCallRedirectionModeListener;
8371 @GuardedBy("mCallRedirectionLock")
8372 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
8373
8374 /**
8375 * @hide
8376 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
8377 * This can be used for functions like call screening or call audio redirection and is reserved
8378 * to system apps with privileged permission.
8379 * @param format the desired audio format for audio playback.
8380 * p>Formats accepted are:
8381 * <ul>
8382 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8383 * <li><em>Channel mask</em> - Mono or Stereo </li>
8384 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8385 * </ul>
8386 *
8387 * @return The AudioTrack used for audio injection
8388 * @throws NullPointerException if AudioFormat argument is null.
8389 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8390 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8391 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8392 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8393 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8394 * or MODE_COMMUNICATION_REDIRECT.
8395 */
8396 @TestApi
8397 @SystemApi
8398 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8399 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
8400 Objects.requireNonNull(format);
8401 checkCallRedirectionFormat(format, true /* isOutput */);
8402
8403 AudioTrack track = null;
8404 int redirectMode = getCallRedirectMode();
8405 if (redirectMode == CALL_REDIRECT_NONE) {
8406 throw new IllegalStateException(
8407 " not available in mode " + AudioSystem.modeToString(getMode()));
8408 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8409 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8410 }
8411
8412 track = new AudioTrack.Builder()
8413 .setAudioAttributes(new AudioAttributes.Builder()
8414 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
8415 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
8416 .build())
8417 .setAudioFormat(format)
8418 .setCallRedirectionMode(redirectMode)
8419 .build();
8420
8421 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
8422 synchronized (mCallRedirectionLock) {
8423 if (mCallRedirectionModeListener == null) {
8424 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8425 try {
8426 addOnModeChangedListener(
8427 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8428 } catch (Exception e) {
8429 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8430 mCallRedirectionModeListener = null;
8431 throw new UnsupportedOperationException(" Cannot register mode listener ");
8432 }
8433 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8434 }
8435 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8436 info.redirectMode = redirectMode;
8437 info.trackOrRecord = new WeakReference<AudioTrack>(track);
8438 mCallIRedirectionClients.add(info);
8439 }
8440 } else {
8441 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
8442 }
8443 return track;
8444 }
8445
8446 /**
8447 * @hide
8448 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
8449 * This can be used for functions like call screening or call audio redirection and is reserved
8450 * to system apps with privileged permission.
8451 * @param format the desired audio format for audio capture.
8452 *<p>Formats accepted are:
8453 * <ul>
8454 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8455 * <li><em>Channel mask</em> - Mono or Stereo </li>
8456 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8457 * </ul>
8458 *
8459 * @return The AudioRecord used for audio extraction
8460 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8461 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8462 * @throws NullPointerException if AudioFormat argument is null.
8463 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8464 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8465 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8466 * or MODE_COMMUNICATION_REDIRECT.
8467 */
8468 @TestApi
8469 @SystemApi
8470 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8471 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
8472 Objects.requireNonNull(format);
8473 checkCallRedirectionFormat(format, false /* isOutput */);
8474
8475 AudioRecord record = null;
8476 int redirectMode = getCallRedirectMode();
8477 if (redirectMode == CALL_REDIRECT_NONE) {
8478 throw new IllegalStateException(
8479 " not available in mode " + AudioSystem.modeToString(getMode()));
8480 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8481 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8482 }
8483
8484 record = new AudioRecord.Builder()
8485 .setAudioAttributes(new AudioAttributes.Builder()
8486 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
8487 .build())
8488 .setAudioFormat(format)
8489 .setCallRedirectionMode(redirectMode)
8490 .build();
8491
8492 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
8493 synchronized (mCallRedirectionLock) {
8494 if (mCallRedirectionModeListener == null) {
8495 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8496 try {
8497 addOnModeChangedListener(
8498 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8499 } catch (Exception e) {
8500 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8501 mCallRedirectionModeListener = null;
8502 throw new UnsupportedOperationException(" Cannot register mode listener ");
8503 }
8504 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8505 }
8506 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8507 info.redirectMode = redirectMode;
8508 info.trackOrRecord = new WeakReference<AudioRecord>(record);
8509 mCallIRedirectionClients.add(info);
8510 }
8511 } else {
8512 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
8513 }
8514 return record;
8515 }
8516
8517 class CallInjectionModeChangedListener implements OnModeChangedListener {
8518 @Override
8519 public void onModeChanged(@AudioMode int mode) {
8520 synchronized (mCallRedirectionLock) {
8521 final ArrayList<CallIRedirectionClientInfo> clientInfos =
8522 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
8523 for (CallIRedirectionClientInfo info : clientInfos) {
8524 Object trackOrRecord = info.trackOrRecord.get();
8525 if (trackOrRecord != null) {
8526 if ((info.redirectMode == CALL_REDIRECT_PSTN
8527 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
8528 && mode != MODE_CALL_REDIRECT)
8529 || (info.redirectMode == CALL_REDIRECT_VOIP
8530 && mode != MODE_IN_COMMUNICATION
8531 && mode != MODE_COMMUNICATION_REDIRECT)) {
8532 if (trackOrRecord instanceof AudioTrack) {
8533 AudioTrack track = (AudioTrack) trackOrRecord;
8534 track.release();
8535 } else {
8536 AudioRecord record = (AudioRecord) trackOrRecord;
8537 record.release();
8538 }
8539 mCallIRedirectionClients.remove(info);
8540 }
8541 }
8542 }
8543 if (mCallIRedirectionClients.isEmpty()) {
8544 try {
8545 if (mCallRedirectionModeListener != null) {
8546 removeOnModeChangedListener(mCallRedirectionModeListener);
8547 }
8548 } catch (Exception e) {
8549 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
8550 } finally {
8551 mCallRedirectionModeListener = null;
8552 mCallIRedirectionClients = null;
8553 }
8554 }
8555 }
8556 }
8557 }
8558
Paul McLeane3383cc2015-05-08 11:41:20 -07008559 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008560 // audio device connection-dependent muting
8561 /**
8562 * @hide
8563 * Mute a set of playback use cases until a given audio device is connected.
8564 * Automatically unmute upon connection of the device, or after the given timeout, whichever
8565 * happens first.
8566 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
8567 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
8568 * device connects
8569 * @param device the audio device expected to connect within the timeout duration
8570 * @param timeout the maximum amount of time to wait for the device connection
8571 * @param timeUnit the unit for the timeout
8572 * @throws IllegalStateException when trying to issue the command while another is already in
8573 * progress and hasn't been cancelled by
8574 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8575 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8576 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8577 */
8578 @SystemApi
8579 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8580 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8581 @NonNull AudioDeviceAttributes device,
8582 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8583 if (timeout <= 0) {
8584 throw new IllegalArgumentException("Timeout must be greater than 0");
8585 }
8586 Objects.requireNonNull(usagesToMute);
8587 if (usagesToMute.length == 0) {
8588 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8589 }
8590 Objects.requireNonNull(device);
8591 Objects.requireNonNull(timeUnit);
8592 try {
8593 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8594 } catch (RemoteException e) {
8595 throw e.rethrowFromSystemServer();
8596 }
8597 }
8598
8599 /**
8600 * @hide
8601 * Query which audio device, if any, is causing some playback use cases to be muted until it
8602 * connects.
8603 * @return the audio device used in
8604 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8605 * if there is no active muting command (either because the muting command was not issued
8606 * or because it timed out)
8607 */
8608 @SystemApi
8609 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8610 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8611 try {
8612 return getService().getMutingExpectedDevice();
8613 } catch (RemoteException e) {
8614 throw e.rethrowFromSystemServer();
8615 }
8616 }
8617
8618 /**
8619 * @hide
8620 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8621 * command.
8622 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8623 * command was issued.
8624 * @throws IllegalStateException when trying to issue the command for a device whose connection
8625 * is not anticipated by a previous call to
8626 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8627 */
8628 @SystemApi
8629 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8630 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8631 throws IllegalStateException {
8632 Objects.requireNonNull(device);
8633 try {
8634 getService().cancelMuteAwaitConnection(device);
8635 } catch (RemoteException e) {
8636 throw e.rethrowFromSystemServer();
8637 }
8638 }
8639
8640 /**
8641 * @hide
8642 * A callback class to receive events about the muting and unmuting of playback use cases
8643 * conditional on the upcoming connection of an audio device.
8644 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8645 */
8646 @SystemApi
8647 public abstract static class MuteAwaitConnectionCallback {
8648
8649 /**
8650 * An event where the expected audio device connected
8651 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8652 */
8653 public static final int EVENT_CONNECTION = 1;
8654 /**
8655 * An event where the expected audio device failed connect before the timeout happened
8656 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8657 */
8658 public static final int EVENT_TIMEOUT = 2;
8659 /**
8660 * An event where the {@code muteAwaitConnection()} command
8661 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
8662 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8663 */
8664 public static final int EVENT_CANCEL = 3;
8665
8666 /** @hide */
8667 @IntDef(flag = false, prefix = "EVENT_", value = {
8668 EVENT_CONNECTION,
8669 EVENT_TIMEOUT,
8670 EVENT_CANCEL }
8671 )
8672 @Retention(RetentionPolicy.SOURCE)
8673 public @interface UnmuteEvent {}
8674
8675 /**
8676 * Called when a number of playback use cases are muted in response to a call to
8677 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
8678 * @param device the audio device whose connection is expected. Playback use cases are
8679 * unmuted when that device connects
8680 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
8681 * playback use cases.
8682 */
8683 public void onMutedUntilConnection(
8684 @NonNull AudioDeviceAttributes device,
8685 @NonNull int[] mutedUsages) {}
8686
8687 /**
8688 * Called when an event occurred that caused playback uses cases to be unmuted
8689 * @param unmuteEvent the nature of the event
8690 * @param device the device that was expected to connect
8691 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
8692 * the event occurred
8693 */
8694 public void onUnmutedEvent(
8695 @UnmuteEvent int unmuteEvent,
8696 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
8697 }
8698
8699
8700 /**
8701 * @hide
8702 * Register a callback to receive updates on the playback muting conditional on a specific
8703 * audio device connection.
8704 * @param executor the {@link Executor} handling the callback
8705 * @param callback the callback to register
8706 */
8707 @SystemApi
8708 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8709 public void registerMuteAwaitConnectionCallback(
8710 @NonNull @CallbackExecutor Executor executor,
8711 @NonNull MuteAwaitConnectionCallback callback) {
8712 synchronized (mMuteAwaitConnectionListenerLock) {
8713 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8714 MuteAwaitConnectionDispatcherStub> res =
8715 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
8716 executor, callback, mMuteAwaitConnectionListeners,
8717 mMuteAwaitConnDispatcherStub,
8718 () -> new MuteAwaitConnectionDispatcherStub(),
8719 stub -> stub.register(true));
8720 mMuteAwaitConnectionListeners = res.first;
8721 mMuteAwaitConnDispatcherStub = res.second;
8722 }
8723 }
8724
8725 /**
8726 * @hide
8727 * Unregister a previously registered callback for playback muting conditional on device
8728 * connection.
8729 * @param callback the callback to unregister
8730 */
8731 @SystemApi
8732 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8733 public void unregisterMuteAwaitConnectionCallback(
8734 @NonNull MuteAwaitConnectionCallback callback) {
8735 synchronized (mMuteAwaitConnectionListenerLock) {
8736 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8737 MuteAwaitConnectionDispatcherStub> res =
8738 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
8739 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
8740 stub -> stub.register(false));
8741 mMuteAwaitConnectionListeners = res.first;
8742 mMuteAwaitConnDispatcherStub = res.second;
8743 }
8744 }
8745
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008746 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008747 * Add UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008748 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008749 * @param assistantUids UIDs of the services that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008750 *
8751 * @hide
8752 */
8753 @SystemApi
8754 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008755 public void addAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008756 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008757 getService().addAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008758 } catch (RemoteException e) {
8759 throw e.rethrowFromSystemServer();
8760 }
8761 }
8762
8763 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008764 * Remove UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008765 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008766 * @param assistantUids UIDs of the services that should be remove.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008767 *
8768 * @hide
8769 */
8770 @SystemApi
8771 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008772 public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008773 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008774 getService().removeAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008775 } catch (RemoteException e) {
8776 throw e.rethrowFromSystemServer();
8777 }
8778 }
8779
8780 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008781 * Get the assistants UIDs that been added with the
8782 * {@link #addAssistantServicesUids(int[])} and not yet removed with
8783 * {@link #removeAssistantServicesUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008784 *
Oscar Azucena3ae33762022-03-04 04:44:59 +00008785 * <p> Note that during native audioserver crash and after boot up the list of assistant
8786 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
8787 * Just after user switch, the list of assistant will also reset to empty.
8788 * In both cases,The component's UID of the assistiant role or assistant setting will be
8789 * automitically added to the list by the audio service.
8790 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008791 * @return array of assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008792 *
8793 * @hide
8794 */
8795 @SystemApi
8796 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008797 public @NonNull int[] getAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008798 try {
8799 int[] uids = getService().getAssistantServicesUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00008800 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008801 } catch (RemoteException e) {
8802 throw e.rethrowFromSystemServer();
8803 }
8804 }
8805
8806 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008807 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
8808 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
8809 * In this manner calling the API with an empty array will remove all UIDs previously set.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008810 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008811 * @param assistantUids UIDs of the services that can be considered active assistant. Can be
8812 * an empty array, for this no UID will be considered active.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008813 *
8814 * <p> Note that during audio service crash reset and after boot up the list of active assistant
Oscar Azucena88467fe2022-02-15 21:55:11 +00008815 * 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 -08008816 * Just after user switch the list of active assistant will also reset to empty.
8817 *
8818 * @hide
8819 */
8820 @SystemApi
8821 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008822 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008823 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008824 getService().setActiveAssistantServiceUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008825 } catch (RemoteException e) {
8826 throw e.rethrowFromSystemServer();
8827 }
8828 }
8829
8830 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008831 * Get active assistant UIDs last set with the
8832 * {@link #setActiveAssistantServiceUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008833 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008834 * @return array of active assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008835 *
8836 * @hide
8837 */
8838 @SystemApi
8839 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008840 public @NonNull int[] getActiveAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008841 try {
8842 int[] uids = getService().getActiveAssistantServiceUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00008843 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008844 } catch (RemoteException e) {
8845 throw e.rethrowFromSystemServer();
8846 }
8847 }
8848
jiabinfe6b7f12022-02-04 18:45:44 +00008849 /**
Shunkai Yao601b6132022-11-22 01:47:48 +00008850 * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio
8851 * HAL found, null will be returned.
jiabinfe6b7f12022-02-04 18:45:44 +00008852 *
Shunkai Yao601b6132022-11-22 01:47:48 +00008853 * @return @see @link #AudioHalVersionInfo The version of Audio HAL.
jiabinfe6b7f12022-02-04 18:45:44 +00008854 * @hide
8855 */
8856 @TestApi
Shunkai Yao601b6132022-11-22 01:47:48 +00008857 public static @Nullable AudioHalVersionInfo getHalVersion() {
jiabinfe6b7f12022-02-04 18:45:44 +00008858 try {
8859 return getService().getHalVersion();
8860 } catch (RemoteException e) {
8861 Log.e(TAG, "Error querying getHalVersion", e);
8862 throw e.rethrowFromSystemServer();
8863 }
8864 }
8865
jiabin89f87ed2022-12-01 22:55:05 +00008866 //====================================================================
8867 // Preferred mixer attributes
8868
8869 /**
8870 * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixe
8871 * attributes via {@link #setPreferredMixerAttributes(
8872 * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}.
8873 * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes, the
8874 * returned list may be empty when devices do not allow dynamic configuration.
8875 *
8876 * @param device the device to query
8877 * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes
8878 * for the given device.
8879 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
8880 */
8881 @NonNull
8882 public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) {
8883 Objects.requireNonNull(device);
8884 List<AudioMixerAttributes> mixerAttrs = new ArrayList<>();
8885 return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs)
8886 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>();
8887 }
8888
8889 /**
8890 * Configures the mixer attributes for a particular {@link AudioAttributes} over a given
8891 * {@link AudioDeviceInfo}.
8892 * <p>When constructing an {@link AudioMixerAttributes} for setting preferred mixer attributes,
8893 * the mixer format must be constructed from an {@link AudioProfile} that can be used to set
8894 * preferred mixer attributes.
8895 * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the
8896 * same uid is routed to the given audio device when calling this API, the output mixer/stream
8897 * will be configured with the values previously set via this API.
8898 * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)}
8899 * to cancel setting mixer attributes for this {@link AudioAttributes}.
8900 *
8901 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
8902 * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When
8903 * playing audio targeted at the given device, use the same attributes for
8904 * playback.
8905 * @param device the device to be routed. Currently, only USB device will be allowed.
8906 * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the
8907 * given device, use the same {@link AudioFormat} for both playback
8908 * and the mixer attributes.
8909 * @return true only if the preferred mixer attributes are set successfully.
8910 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
8911 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
8912 */
8913 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
8914 public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
8915 @NonNull AudioDeviceInfo device,
8916 @NonNull AudioMixerAttributes mixerAttributes) {
8917 Objects.requireNonNull(attributes);
8918 Objects.requireNonNull(device);
8919 Objects.requireNonNull(mixerAttributes);
8920 try {
8921 final int status = getService().setPreferredMixerAttributes(
8922 attributes, device.getId(), mixerAttributes);
8923 return status == AudioSystem.SUCCESS;
8924 } catch (RemoteException e) {
8925 throw e.rethrowFromSystemServer();
8926 }
8927 }
8928
8929 /**
8930 * Returns current preferred mixer attributes that is set via
8931 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
8932 *
8933 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
8934 * @param device the expected routing device
8935 * @return the preferred mixer attributes, which will be null when no preferred mixer attributes
8936 * have been set, or when they have been cleared.
8937 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
8938 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
8939 */
8940 @Nullable
8941 public AudioMixerAttributes getPreferredMixerAttributes(
8942 @NonNull AudioAttributes attributes,
8943 @NonNull AudioDeviceInfo device) {
8944 Objects.requireNonNull(attributes);
8945 Objects.requireNonNull(device);
8946 List<AudioMixerAttributes> mixerAttrList = new ArrayList<>();
8947 int ret = AudioSystem.getPreferredMixerAttributes(
8948 attributes, device.getId(), mixerAttrList);
8949 if (ret == AudioSystem.SUCCESS) {
8950 return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0);
8951 } else {
8952 Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret);
8953 return null;
8954 }
8955 }
8956
8957 /**
8958 * Clears the current preferred mixer attributes that were previously set via
8959 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
8960 *
8961 * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared.
8962 * @param device the expected routing device
8963 * @return true only if the preferred mixer attributes are removed successfully.
8964 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
8965 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
8966 */
8967 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
8968 public boolean clearPreferredMixerAttributes(
8969 @NonNull AudioAttributes attributes,
8970 @NonNull AudioDeviceInfo device) {
8971 Objects.requireNonNull(attributes);
8972 Objects.requireNonNull(device);
8973 try {
8974 final int status = getService().clearPreferredMixerAttributes(
8975 attributes, device.getId());
8976 return status == AudioSystem.SUCCESS;
8977 } catch (RemoteException e) {
8978 throw e.rethrowFromSystemServer();
8979 }
8980 }
8981
8982 /**
8983 * Interface to be notified of changes in the preferred mixer attributes.
8984 * <p>Note that this listener will only be invoked whenever
8985 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
8986 * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device
8987 * disconnection causes a change in preferred mixer attributes.
8988 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
8989 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
8990 */
8991 public interface OnPreferredMixerAttributesChangedListener {
8992 /**
8993 * Called on the listener to indicate that the preferred mixer attributes for the audio
8994 * attributes over the given device has changed.
8995 *
8996 * @param attributes the audio attributes for playback
8997 * @param device the targeted device
8998 * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for
8999 * preferred mixer attributes or null if preferred mixer attributes
9000 * is cleared
9001 */
9002 void onPreferredMixerAttributesChanged(
9003 @NonNull AudioAttributes attributes,
9004 @NonNull AudioDeviceInfo device,
9005 @Nullable AudioMixerAttributes mixerAttributes);
9006 }
9007
9008 /**
9009 * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the
9010 * {@link PreferredMixerAttributesDispatcherStub}.
9011 */
9012 private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener>
9013 mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager();
9014
9015 /**
9016 * Adds a listener for being notified of changes to the preferred mixer attributes.
9017 * @param executor the executor to execute the callback
9018 * @param listener the listener to be notified of changes in the preferred mixer attributes.
9019 */
9020 public void addOnPreferredMixerAttributesChangedListener(
9021 @NonNull @CallbackExecutor Executor executor,
9022 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9023 Objects.requireNonNull(executor);
9024 Objects.requireNonNull(listener);
9025 mPrefMixerAttributesListenerMgr.addListener(executor, listener,
9026 "addOnPreferredMixerAttributesChangedListener",
9027 () -> new PreferredMixerAttributesDispatcherStub());
9028 }
9029
9030 /**
9031 * Removes a previously added listener of changes to the preferred mixer attributes.
9032 * @param listener the listener to be notified of changes in the preferred mixer attributes,
9033 * which were added via {@link #addOnPreferredMixerAttributesChangedListener(
9034 * Executor, OnPreferredMixerAttributesChangedListener)}.
9035 */
9036 public void removeOnPreferredMixerAttributesChangedListener(
9037 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9038 Objects.requireNonNull(listener);
9039 mPrefMixerAttributesListenerMgr.removeListener(listener,
9040 "removeOnPreferredMixerAttributesChangedListener");
9041 }
9042
9043 private final class PreferredMixerAttributesDispatcherStub
9044 extends IPreferredMixerAttributesDispatcher.Stub
9045 implements CallbackUtil.DispatcherStub {
9046
9047 @Override
9048 public void register(boolean register) {
9049 try {
9050 if (register) {
9051 getService().registerPreferredMixerAttributesDispatcher(this);
9052 } else {
9053 getService().unregisterPreferredMixerAttributesDispatcher(this);
9054 }
9055 } catch (RemoteException e) {
9056 e.rethrowFromSystemServer();
9057 }
9058 }
9059
9060 @Override
9061 public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr,
9062 int deviceId,
9063 @Nullable AudioMixerAttributes mixerAttr) {
9064 // TODO: If the device is disconnected, we may not be able to find the device with
9065 // given device id. We need a better to carry the device information via binder.
9066 AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS);
9067 if (device == null) {
9068 Log.d(TAG, "Drop preferred mixer attributes changed as the device("
9069 + deviceId + ") is disconnected");
9070 return;
9071 }
9072 mPrefMixerAttributesListenerMgr.callListeners(
9073 (listener) -> listener.onPreferredMixerAttributesChanged(
9074 attr, device, mixerAttr));
9075 }
9076 }
9077
Eric Laurent3c474bc2022-12-16 17:24:32 +01009078 /**
9079 * Requests if the implementation supports controlling the latency modes
9080 * over the Bluetooth A2DP or LE Audio links.
9081 *
9082 * @return true if supported, false otherwise
9083 *
9084 * @hide
9085 */
9086 @SystemApi
9087 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
9088 public boolean supportsBluetoothVariableLatency() {
9089 try {
9090 return getService().supportsBluetoothVariableLatency();
9091 } catch (RemoteException e) {
9092 throw e.rethrowFromSystemServer();
9093 }
9094 }
9095
9096 /**
9097 * Enables or disables the variable Bluetooth latency control mechanism in the
9098 * audio framework and the audio HAL. This does not apply to the latency mode control
9099 * on the spatializer output as this is a built-in feature.
9100 *
9101 * @hide
9102 */
9103 @SystemApi
9104 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
9105 public void setBluetoothVariableLatencyEnabled(boolean enabled) {
9106 try {
9107 getService().setBluetoothVariableLatencyEnabled(enabled);
9108 } catch (RemoteException e) {
9109 throw e.rethrowFromSystemServer();
9110 }
9111 }
9112
9113 /**
9114 * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
9115 * @hide
9116 */
9117 @SystemApi
9118 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
9119 public boolean isBluetoothVariableLatencyEnabled() {
9120 try {
9121 return getService().isBluetoothVariableLatencyEnabled();
9122 } catch (RemoteException e) {
9123 throw e.rethrowFromSystemServer();
9124 }
9125 }
9126
jiabin89f87ed2022-12-01 22:55:05 +00009127 //====================================================================
9128 // Mute await connection
9129
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009130 private final Object mMuteAwaitConnectionListenerLock = new Object();
9131
9132 @GuardedBy("mMuteAwaitConnectionListenerLock")
9133 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
9134 mMuteAwaitConnectionListeners;
9135
9136 @GuardedBy("mMuteAwaitConnectionListenerLock")
9137 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
9138
9139 private final class MuteAwaitConnectionDispatcherStub
9140 extends IMuteAwaitConnectionCallback.Stub {
9141 public void register(boolean register) {
9142 try {
9143 getService().registerMuteAwaitConnectionDispatcher(this, register);
9144 } catch (RemoteException e) {
9145 throw e.rethrowFromSystemServer();
9146 }
9147 }
9148
9149 @Override
9150 @SuppressLint("GuardedBy") // lock applied inside callListeners method
9151 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
9152 int[] mutedUsages) {
9153 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
9154 mMuteAwaitConnectionListenerLock,
9155 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
9156 }
9157
9158 @Override
9159 @SuppressLint("GuardedBy") // lock applied inside callListeners method
9160 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
9161 int[] mutedUsages) {
9162 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
9163 mMuteAwaitConnectionListenerLock,
9164 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
9165 }
9166 }
9167
9168 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07009169 // Inner classes
9170 //--------------------
9171 /**
9172 * Helper class to handle the forwarding of native events to the appropriate listener
9173 * (potentially) handled in a different thread.
9174 */
9175 private class NativeEventHandlerDelegate {
9176 private final Handler mHandler;
9177
Paul McLean03346882015-05-12 15:36:56 -07009178 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07009179 Handler handler) {
9180 // find the looper for our new event handler
9181 Looper looper;
9182 if (handler != null) {
9183 looper = handler.getLooper();
9184 } else {
9185 // no given handler, use the looper the addListener call was called in
9186 looper = Looper.getMainLooper();
9187 }
9188
9189 // construct the event handler with this looper
9190 if (looper != null) {
9191 // implement the event handler delegate
9192 mHandler = new Handler(looper) {
9193 @Override
9194 public void handleMessage(Message msg) {
9195 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07009196 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07009197 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07009198 if (callback != null) {
9199 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07009200 }
9201 break;
Paul McLean03346882015-05-12 15:36:56 -07009202
9203 case MSG_DEVICES_DEVICES_REMOVED:
9204 if (callback != null) {
9205 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
9206 }
9207 break;
9208
Paul McLeane3383cc2015-05-08 11:41:20 -07009209 default:
9210 Log.e(TAG, "Unknown native event type: " + msg.what);
9211 break;
9212 }
9213 }
9214 };
9215 } else {
9216 mHandler = null;
9217 }
9218 }
9219
9220 Handler getHandler() {
9221 return mHandler;
9222 }
9223 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08009224}