blob: 59591c92d246250f31072883ff33ab36ee457fe5 [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
Jack Diver4f2f43d2023-01-23 10:40:14 +000019import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010020import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
21import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
22
Jean-Michel Trivic4557822023-01-23 18:19:52 +000023import android.Manifest;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080024import android.annotation.CallbackExecutor;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080025import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070026import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080027import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070028import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060029import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.annotation.SdkConstant;
31import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070032import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090033import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060034import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070035import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050036import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070037import android.app.PendingIntent;
Eric Laurent1c3408f2021-11-09 12:09:54 +010038import android.app.compat.CompatChanges;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080039import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070040import android.bluetooth.BluetoothDevice;
Patty46694212021-11-04 21:03:32 +080041import android.bluetooth.BluetoothLeAudioCodecConfig;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010042import android.companion.virtual.VirtualDeviceManager;
Eric Laurent1c3408f2021-11-09 12:09:54 +010043import android.compat.annotation.ChangeId;
44import android.compat.annotation.EnabledSince;
Yan Han31b10112023-02-13 17:25:46 +010045import android.compat.annotation.Overridable;
Artur Satayev53fe9662019-12-10 17:47:55 +000046import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070047import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070049import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080050import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080051import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070052import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080053import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070054import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070055import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020056import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080057import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070058import android.media.session.MediaController;
59import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070060import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070061import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070062import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070064import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.os.Handler;
66import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080067import android.os.Looper;
68import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.os.RemoteException;
70import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050071import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010072import android.os.UserHandle;
Lais Andrade724d0cd2021-11-03 19:46:21 +000073import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080074import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070075import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080077import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070078import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080080import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020081import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080082
jiabinc0f49442018-01-05 10:23:50 -080083import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080084import java.lang.annotation.Retention;
85import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070086import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080087import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070088import java.util.Arrays;
Dorin Drimusdaeb6a92021-12-22 11:46:26 +010089import java.util.Collections;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080090import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070091import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090092import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080093import java.util.List;
jiabin39940752018-04-02 18:18:45 -070094import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070095import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090096import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070097import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080098import java.util.concurrent.Executor;
Eric Laurent78eef3a2021-11-09 16:10:42 +010099import java.util.concurrent.Executors;
Jean-Michel Trivi933bf142021-11-19 16:18:52 -0800100import java.util.concurrent.TimeUnit;
Eric Laurent700e7342014-05-02 18:33:15 -0700101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102/**
103 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600105@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106public class AudioManager {
107
Marco Nelissen29f16932015-04-17 09:50:56 -0700108 private Context mOriginalContext;
109 private Context mApplicationContext;
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000110 private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100111 private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized.
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800112 private static final String TAG = "AudioManager";
113 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800114 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200115 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
116 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117
jiabin0f3339c2021-07-09 11:50:07 -0700118 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 /**
121 * Broadcast intent, a hint for applications that audio is about to become
122 * 'noisy' due to a change in audio outputs. For example, this intent may
123 * be sent when a wired headset is unplugged, or when an A2DP audio
124 * sink is disconnected, and the audio system is about to automatically
125 * switch audio route to the speaker. Applications that are controlling
126 * audio streams may consider pausing, reducing volume or some other action
127 * on receipt of this intent so as not to surprise the user with audio
128 * from the speaker.
129 */
130 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
131 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
132
133 /**
134 * Sticky broadcast intent action indicating that the ringer mode has
135 * changed. Includes the new ringer mode.
136 *
137 * @see #EXTRA_RINGER_MODE
138 */
139 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
140 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
141
142 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500143 * @hide
144 * Sticky broadcast intent action indicating that the internal ringer mode has
145 * changed. Includes the new ringer mode.
146 *
147 * @see #EXTRA_RINGER_MODE
148 */
149 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
150 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
151 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
152
153 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 * The new ringer mode.
155 *
156 * @see #RINGER_MODE_CHANGED_ACTION
157 * @see #RINGER_MODE_NORMAL
158 * @see #RINGER_MODE_SILENT
159 * @see #RINGER_MODE_VIBRATE
160 */
161 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
162
163 /**
164 * Broadcast intent action indicating that the vibrate setting has
165 * changed. Includes the vibrate type and its new setting.
166 *
167 * @see #EXTRA_VIBRATE_TYPE
168 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700169 * @deprecated Applications should maintain their own vibrate policy based on
170 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 */
172 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500173 public static final String VIBRATE_SETTING_CHANGED_ACTION =
174 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
176 /**
177 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700178 * Includes the stream, the new volume and previous volumes.
179 * Notes:
180 * - for internal platform use only, do not make public,
181 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 *
183 * @see #EXTRA_VOLUME_STREAM_TYPE
184 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800185 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 */
187 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100188 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
190
191 /**
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800192 * @hide Broadcast intent when the volume for a particular stream type changes.
193 * Includes the stream, the new volume and previous volumes.
194 * Notes:
195 * - for internal platform use only, do not make public,
196 * - never used for "remote" volume changes
197 *
198 * @see #EXTRA_VOLUME_STREAM_TYPE
199 * @see #EXTRA_VOLUME_STREAM_VALUE
200 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
201 */
202 @SystemApi
203 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
204 @SuppressLint("ActionValue")
205 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
206
207 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400208 * @hide Broadcast intent when the devices for a particular stream type changes.
209 * Includes the stream, the new devices and previous devices.
210 * Notes:
211 * - for internal platform use only, do not make public,
212 * - never used for "remote" volume changes
213 *
214 * @see #EXTRA_VOLUME_STREAM_TYPE
215 * @see #EXTRA_VOLUME_STREAM_DEVICES
216 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
217 * @see #getDevicesForStream
218 */
219 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
220 public static final String STREAM_DEVICES_CHANGED_ACTION =
221 "android.media.STREAM_DEVICES_CHANGED_ACTION";
222
223 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800224 * @hide Broadcast intent when a stream mute state changes.
225 * Includes the stream that changed and the new mute state
226 *
227 * @see #EXTRA_VOLUME_STREAM_TYPE
228 * @see #EXTRA_STREAM_VOLUME_MUTED
229 */
230 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
231 public static final String STREAM_MUTE_CHANGED_ACTION =
232 "android.media.STREAM_MUTE_CHANGED_ACTION";
233
234 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500235 * @hide Broadcast intent when the master mute state changes.
236 * Includes the the new volume
237 *
238 * @see #EXTRA_MASTER_VOLUME_MUTED
239 */
240 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
241 public static final String MASTER_MUTE_CHANGED_ACTION =
242 "android.media.MASTER_MUTE_CHANGED_ACTION";
243
244 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 * The new vibrate setting for a particular type.
246 *
247 * @see #VIBRATE_SETTING_CHANGED_ACTION
248 * @see #EXTRA_VIBRATE_TYPE
249 * @see #VIBRATE_SETTING_ON
250 * @see #VIBRATE_SETTING_OFF
251 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700252 * @deprecated Applications should maintain their own vibrate policy based on
253 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 */
255 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
256
257 /**
258 * The vibrate type whose setting has changed.
259 *
260 * @see #VIBRATE_SETTING_CHANGED_ACTION
261 * @see #VIBRATE_TYPE_NOTIFICATION
262 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700263 * @deprecated Applications should maintain their own vibrate policy based on
264 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 */
266 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
267
268 /**
269 * @hide The stream type for the volume changed intent.
270 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800271 @SystemApi
272 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
274
275 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700276 * @hide
277 * The stream type alias for the volume changed intent.
278 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
279 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
280 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
281 * {@link #STREAM_MUSIC} on others (e.g. a television).
282 */
283 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
284 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
285
286 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 * @hide The volume associated with the stream for the volume changed intent.
288 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800289 @SystemApi
290 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 public static final String EXTRA_VOLUME_STREAM_VALUE =
292 "android.media.EXTRA_VOLUME_STREAM_VALUE";
293
Eric Laurent9ce379a2010-02-16 06:00:26 -0800294 /**
295 * @hide The previous volume associated with the stream for the volume changed intent.
296 */
297 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
298 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
299
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500300 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400301 * @hide The devices associated with the stream for the stream devices changed intent.
302 */
303 public static final String EXTRA_VOLUME_STREAM_DEVICES =
304 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
305
306 /**
307 * @hide The previous devices associated with the stream for the stream devices changed intent.
308 */
309 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
310 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
311
312 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500313 * @hide The new master volume mute state for the master mute changed intent.
314 * Value is boolean
315 */
316 public static final String EXTRA_MASTER_VOLUME_MUTED =
317 "android.media.EXTRA_MASTER_VOLUME_MUTED";
318
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700319 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800320 * @hide The new stream volume mute state for the stream mute changed intent.
321 * Value is boolean
322 */
323 public static final String EXTRA_STREAM_VOLUME_MUTED =
324 "android.media.EXTRA_STREAM_VOLUME_MUTED";
325
326 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700327 * Broadcast Action: Wired Headset plugged in or unplugged.
328 *
329 * You <em>cannot</em> receive this through components declared
330 * in manifests, only by explicitly registering for it with
331 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
332 * Context.registerReceiver()}.
333 *
334 * <p>The intent will have the following extra values:
335 * <ul>
336 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
337 * <li><em>name</em> - Headset type, human readable string </li>
338 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
339 * </ul>
340 * </ul>
341 */
342 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
343 public static final String ACTION_HEADSET_PLUG =
344 "android.intent.action.HEADSET_PLUG";
345
346 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200347 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700348 *
349 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
350 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
351 * <p>It can only be received by explicitly registering for it with
352 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
353 */
354 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
355 public static final String ACTION_HDMI_AUDIO_PLUG =
356 "android.media.action.HDMI_AUDIO_PLUG";
357
358 /**
359 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
360 * or unplugged.
361 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
362 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700363 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700364
365 /**
366 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
367 * supported by the HDMI device.
368 * The corresponding integer value is only available when the device is plugged in (as expressed
369 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
370 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700371 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700372
373 /**
374 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
375 * the connected HDMI device.
376 * The corresponding array of encoding values is only available when the device is plugged in
377 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
378 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
379 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
380 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700381 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700382
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700383 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700385 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700387 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700389 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700391 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700393 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700395 /** @hide Used to identify the volume of audio streams for phone calls when connected
396 * to bluetooth */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800397 @SystemApi
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700399 /** @hide Used to identify the volume of audio streams for enforced system sounds
400 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100401 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700402 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700403 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700404 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700405 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
406 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100407 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700408 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800409 /** Used to identify the volume of audio streams for accessibility prompts */
410 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000411 /** @hide Used to identify the volume of audio streams for virtual assistant */
412 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +0000413 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000414 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 /** Number of audio streams */
417 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700418 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 */
Eric Laurenta553c252009-07-17 12:17:14 -0700420 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421
Paul McLeand6f87c82021-03-31 13:02:41 -0600422 /** @hide */
423 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
424 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
425 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
426 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
427
428 /** @hide */
429 @TestApi
430 public static final int[] getPublicStreamTypes() {
431 return PUBLIC_STREAM_TYPES;
432 }
433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 /**
435 * Increase the ringer volume.
436 *
437 * @see #adjustVolume(int, int)
438 * @see #adjustStreamVolume(int, int, int)
439 */
440 public static final int ADJUST_RAISE = 1;
441
442 /**
443 * Decrease the ringer volume.
444 *
445 * @see #adjustVolume(int, int)
446 * @see #adjustStreamVolume(int, int, int)
447 */
448 public static final int ADJUST_LOWER = -1;
449
450 /**
451 * Maintain the previous ringer volume. This may be useful when needing to
452 * show the volume toast without actually modifying the volume.
453 *
454 * @see #adjustVolume(int, int)
455 * @see #adjustStreamVolume(int, int, int)
456 */
457 public static final int ADJUST_SAME = 0;
458
RoboErik4197cb62015-01-21 15:45:32 -0800459 /**
460 * Mute the volume. Has no effect if the stream is already muted.
461 *
462 * @see #adjustVolume(int, int)
463 * @see #adjustStreamVolume(int, int, int)
464 */
465 public static final int ADJUST_MUTE = -100;
466
467 /**
468 * Unmute the volume. Has no effect if the stream is not muted.
469 *
470 * @see #adjustVolume(int, int)
471 * @see #adjustStreamVolume(int, int, int)
472 */
473 public static final int ADJUST_UNMUTE = 100;
474
475 /**
476 * Toggle the mute state. If muted the stream will be unmuted. If not muted
477 * the stream will be muted.
478 *
479 * @see #adjustVolume(int, int)
480 * @see #adjustStreamVolume(int, int, int)
481 */
482 public static final int ADJUST_TOGGLE_MUTE = 101;
483
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700484 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800485 @IntDef(flag = false, prefix = "ADJUST", value = {
486 ADJUST_RAISE,
487 ADJUST_LOWER,
488 ADJUST_SAME,
489 ADJUST_MUTE,
490 ADJUST_UNMUTE,
491 ADJUST_TOGGLE_MUTE }
492 )
493 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800494 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800495
496 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700497 public static final String adjustToString(int adj) {
498 switch (adj) {
499 case ADJUST_RAISE: return "ADJUST_RAISE";
500 case ADJUST_LOWER: return "ADJUST_LOWER";
501 case ADJUST_SAME: return "ADJUST_SAME";
502 case ADJUST_MUTE: return "ADJUST_MUTE";
503 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
504 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
505 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
506 }
507 }
508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 // Flags should be powers of 2!
510
511 /**
512 * Show a toast containing the current volume.
513 *
514 * @see #adjustStreamVolume(int, int, int)
515 * @see #adjustVolume(int, int)
516 * @see #setStreamVolume(int, int, int)
517 * @see #setRingerMode(int)
518 */
519 public static final int FLAG_SHOW_UI = 1 << 0;
520
521 /**
522 * Whether to include ringer modes as possible options when changing volume.
523 * For example, if true and volume level is 0 and the volume is adjusted
524 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
525 * vibrate mode.
526 * <p>
527 * By default this is on for the ring stream. If this flag is included,
528 * this behavior will be present regardless of the stream type being
529 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700530 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 * @see #adjustVolume(int, int)
532 * @see #adjustStreamVolume(int, int, int)
533 */
534 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
535
536 /**
537 * Whether to play a sound when changing the volume.
538 * <p>
539 * If this is given to {@link #adjustVolume(int, int)} or
540 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
541 * in some cases (for example, the decided stream type is not
542 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
543 * downward).
544 *
545 * @see #adjustStreamVolume(int, int, int)
546 * @see #adjustVolume(int, int)
547 * @see #setStreamVolume(int, int, int)
548 */
549 public static final int FLAG_PLAY_SOUND = 1 << 2;
550
551 /**
552 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
553 * changing volume).
554 */
555 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
556
557 /**
558 * Whether to vibrate if going into the vibrate ringer mode.
559 */
560 public static final int FLAG_VIBRATE = 1 << 4;
561
562 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700563 * Indicates to VolumePanel that the volume slider should be disabled as user
564 * cannot change the stream volume
565 * @hide
566 */
567 public static final int FLAG_FIXED_VOLUME = 1 << 5;
568
569 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700570 * Indicates the volume set/adjust call is for Bluetooth absolute volume
571 * @hide
572 */
Roopa Sattirajufb933242022-01-30 13:27:58 -0800573 @SystemApi
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700574 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
575
576 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400577 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
578 * @hide
579 */
580 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
581
582 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900583 * Indicates the volume call is for Hdmi Cec system audio volume
584 * @hide
585 */
586 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
587
588 /**
RoboErik3c45c292014-07-08 16:47:31 -0700589 * Indicates that this should only be handled if media is actively playing.
590 * @hide
591 */
592 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
593
594 /**
John Spurlock35134602014-07-24 18:10:48 -0400595 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
596 * @hide
597 */
598 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
599
600 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500601 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
602 * @hide
603 */
604 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
605
John Spurlockb94f2d62015-03-17 14:11:57 -0400606 /**
607 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900608 * This flag can be used in the places in order to denote (or check) that a volume adjustment
609 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400610 * @hide
611 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900612 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900613 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400614
Yan Han7d419822022-01-31 19:10:16 +0100615 /**
616 * Indicates that an absolute volume controller is notifying AudioService of a change in the
617 * volume or mute status of an external audio system.
618 * @hide
619 */
620 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
621
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900622 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100623 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200624 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100625 ENCODED_SURROUND_OUTPUT_AUTO,
626 ENCODED_SURROUND_OUTPUT_NEVER,
627 ENCODED_SURROUND_OUTPUT_ALWAYS,
628 ENCODED_SURROUND_OUTPUT_MANUAL
629 })
630 @Retention(RetentionPolicy.SOURCE)
631 public @interface EncodedSurroundOutputMode {}
632
633 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200634 * The mode for surround sound formats is unknown.
635 */
636 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
637
638 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100639 * The surround sound formats are available for use if they are detected. This is the default
640 * mode.
641 */
642 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
643
644 /**
645 * The surround sound formats are NEVER available, even if they are detected by the hardware.
646 * Those formats will not be reported.
647 */
648 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
649
650 /**
651 * The surround sound formats are ALWAYS available, even if they are not detected by the
652 * hardware. Those formats will be reported as part of the HDMI output capability.
653 * Applications are then free to use either PCM or encoded output.
654 */
655 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
656
657 /**
658 * Surround sound formats are available according to the choice of user, even if they are not
659 * detected by the hardware. Those formats will be reported as part of the HDMI output
660 * capability. Applications are then free to use either PCM or encoded output.
661 */
662 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
663
664 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900665 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900666 FLAG_SHOW_UI,
667 FLAG_ALLOW_RINGER_MODES,
668 FLAG_PLAY_SOUND,
669 FLAG_REMOVE_SOUND_AND_VIBRATE,
670 FLAG_VIBRATE,
671 FLAG_FIXED_VOLUME,
672 FLAG_BLUETOOTH_ABS_VOLUME,
673 FLAG_SHOW_SILENT_HINT,
674 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
675 FLAG_ACTIVE_MEDIA_ONLY,
676 FLAG_SHOW_UI_WARNINGS,
677 FLAG_SHOW_VIBRATE_HINT,
678 FLAG_FROM_KEY,
Yan Han7d419822022-01-31 19:10:16 +0100679 FLAG_ABSOLUTE_VOLUME,
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900680 })
681 @Retention(RetentionPolicy.SOURCE)
682 public @interface Flags {}
683
Hyundo Moonca0080d2018-12-26 16:16:55 +0900684 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
685 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
686
687 static {
688 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
689 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
690 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
691 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
692 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
693 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
694 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
695 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
696 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
697 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
698 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
699 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
700 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
Yan Han7d419822022-01-31 19:10:16 +0100701 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
Hyundo Moonca0080d2018-12-26 16:16:55 +0900702 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500703
704 /** @hide */
705 public static String flagsToString(int flags) {
706 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900707 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
708 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500709 if ((flags & flag) != 0) {
710 if (sb.length() > 0) {
711 sb.append(',');
712 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900713 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500714 flags &= ~flag;
715 }
716 }
717 if (flags != 0) {
718 if (sb.length() > 0) {
719 sb.append(',');
720 }
721 sb.append(flags);
722 }
723 return sb.toString();
724 }
725
726 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 * Ringer mode that will be silent and will not vibrate. (This overrides the
728 * vibrate setting.)
729 *
730 * @see #setRingerMode(int)
731 * @see #getRingerMode()
732 */
733 public static final int RINGER_MODE_SILENT = 0;
734
735 /**
736 * Ringer mode that will be silent and will vibrate. (This will cause the
737 * phone ringer to always vibrate, but the notification vibrate to only
738 * vibrate if set.)
739 *
740 * @see #setRingerMode(int)
741 * @see #getRingerMode()
742 */
743 public static final int RINGER_MODE_VIBRATE = 1;
744
745 /**
746 * Ringer mode that may be audible and may vibrate. It will be audible if
747 * the volume before changing out of this mode was audible. It will vibrate
748 * if the vibrate setting is on.
749 *
750 * @see #setRingerMode(int)
751 * @see #getRingerMode()
752 */
753 public static final int RINGER_MODE_NORMAL = 2;
754
John Spurlock97559372014-10-24 16:27:36 -0400755 /**
756 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
757 * @hide
758 */
759 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 /**
762 * Vibrate type that corresponds to the ringer.
763 *
764 * @see #setVibrateSetting(int, int)
765 * @see #getVibrateSetting(int)
766 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700767 * @deprecated Applications should maintain their own vibrate policy based on
768 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 */
770 public static final int VIBRATE_TYPE_RINGER = 0;
771
772 /**
773 * Vibrate type that corresponds to notifications.
774 *
775 * @see #setVibrateSetting(int, int)
776 * @see #getVibrateSetting(int)
777 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700778 * @deprecated Applications should maintain their own vibrate policy based on
779 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 */
781 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
782
783 /**
784 * Vibrate setting that suggests to never vibrate.
785 *
786 * @see #setVibrateSetting(int, int)
787 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700788 * @deprecated Applications should maintain their own vibrate policy based on
789 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 */
791 public static final int VIBRATE_SETTING_OFF = 0;
792
793 /**
794 * Vibrate setting that suggests to vibrate when possible.
795 *
796 * @see #setVibrateSetting(int, int)
797 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700798 * @deprecated Applications should maintain their own vibrate policy based on
799 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 */
801 public static final int VIBRATE_SETTING_ON = 1;
802
803 /**
804 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
805 * mode.
806 *
807 * @see #setVibrateSetting(int, int)
808 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700809 * @deprecated Applications should maintain their own vibrate policy based on
810 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 */
812 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
813
814 /**
815 * Suggests using the default stream type. This may not be used in all
816 * places a stream type is needed.
817 */
818 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
819
820 private static IAudioService sService;
821
822 /**
823 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800824 * For test purposes only, will throw NPE with some methods that require a Context.
825 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000826 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800827 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800828 }
829
830 /**
831 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100833 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700835 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 }
837
Marco Nelissen29f16932015-04-17 09:50:56 -0700838 private Context getContext() {
839 if (mApplicationContext == null) {
840 setContext(mOriginalContext);
841 }
842 if (mApplicationContext != null) {
843 return mApplicationContext;
844 }
845 return mOriginalContext;
846 }
847
848 private void setContext(Context context) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000849 mOriginalContextDeviceId = context.getDeviceId();
Marco Nelissen29f16932015-04-17 09:50:56 -0700850 mApplicationContext = context.getApplicationContext();
851 if (mApplicationContext != null) {
852 mOriginalContext = null;
853 } else {
854 mOriginalContext = context;
855 }
jiabin0f3339c2021-07-09 11:50:07 -0700856 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700857 }
858
Mathew Inwood31a792a2018-08-17 08:54:26 +0100859 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700860 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 {
862 if (sService != null) {
863 return sService;
864 }
865 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
866 sService = IAudioService.Stub.asInterface(b);
867 return sService;
868 }
869
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100870 private VirtualDeviceManager getVirtualDeviceManager() {
871 if (mVirtualDeviceManager != null) {
872 return mVirtualDeviceManager;
873 }
874 mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class);
875 return mVirtualDeviceManager;
876 }
877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700879 * Sends a simulated key event for a media button.
880 * To simulate a key press, you must first send a KeyEvent built with a
881 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
882 * action.
883 * <p>The key event will be sent to the current media key event consumer which registered with
884 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
885 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
886 * {@link KeyEvent#KEYCODE_MUTE},
887 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
888 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
889 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
890 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
891 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
892 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
893 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
894 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
895 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
896 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
897 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
898 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
899 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700900 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700901 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700902 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700903 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700904 }
905
906 /**
907 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700908 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800909 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700910 /*
911 * If the user hits another key within the play sound delay, then
912 * cancel the sound
913 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800914 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700915 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
916 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
Santiago Seifert75969912023-01-18 11:11:30 +0000917 && AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700918 /*
919 * The user has hit another key during the delay (e.g., 300ms)
920 * since the last volume key up, so cancel any sounds.
921 */
John Spurlockee5ad722015-03-03 16:17:21 -0500922 adjustSuggestedStreamVolume(ADJUST_SAME,
923 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700924 }
925 }
926
927 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700928 * Indicates if the device implements a fixed volume policy.
929 * <p>Some devices may not have volume control and may operate at a fixed volume,
930 * and may not enable muting or changing the volume of audio streams.
931 * This method will return true on such devices.
932 * <p>The following APIs have no effect when volume is fixed:
933 * <ul>
934 * <li> {@link #adjustVolume(int, int)}
935 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
936 * <li> {@link #adjustStreamVolume(int, int, int)}
937 * <li> {@link #setStreamVolume(int, int, int)}
938 * <li> {@link #setRingerMode(int)}
939 * <li> {@link #setStreamSolo(int, boolean)}
940 * <li> {@link #setStreamMute(int, boolean)}
941 * </ul>
942 */
943 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700944 boolean res = false;
945 try {
946 res = getService().isVolumeFixed();
947 } catch (RemoteException e) {
948 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700949 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700950 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700951 }
952
953 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700955 * <p>
956 * This method should only be used by applications that replace the platform-wide
957 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700958 * <p>This method has no effect if the device implements a fixed volume policy
959 * as indicated by {@link #isVolumeFixed()}.
960 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
961 * unless the app has been granted Do Not Disturb Access.
962 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 *
964 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800965 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
966 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 * @param direction The direction to adjust the volume. One of
968 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
969 * {@link #ADJUST_SAME}.
970 * @param flags One or more flags.
971 * @see #adjustVolume(int, int)
972 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700973 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
974 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 */
976 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700977 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 try {
John Wu4f7e5102021-06-22 17:29:11 +0000979 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
980 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700982 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 }
984 }
985
986 /**
987 * Adjusts the volume of the most relevant stream. For example, if a call is
988 * active, it will have the highest priority regardless of if the in-call
989 * screen is showing. Another example, if music is playing in the background
990 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700991 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800992 * This method should only be used by applications that replace the
993 * platform-wide management of audio settings or the main telephony
994 * application.
995 * <p>
996 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700997 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800998 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001000 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1001 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1002 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 * @param flags One or more flags.
1004 * @see #adjustSuggestedStreamVolume(int, int, int)
1005 * @see #adjustStreamVolume(int, int, int)
1006 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001007 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 */
1009 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001010 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001011 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 }
1013
1014 /**
1015 * Adjusts the volume of the most relevant stream, or the given fallback
1016 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001017 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001018 * This method should only be used by applications that replace the
1019 * platform-wide management of audio settings or the main telephony
1020 * application.
1021 * <p>
1022 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001023 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001024 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001026 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1027 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1028 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001030 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1031 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 * @param flags One or more flags.
1033 * @see #adjustVolume(int, int)
1034 * @see #adjustStreamVolume(int, int, int)
1035 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001036 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 */
1038 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001039 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001040 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001041 }
1042
John Spurlockee5ad722015-03-03 16:17:21 -05001043 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001044 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001045 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001046 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001047 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001048 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001049 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001050 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001051 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001052 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
1054 }
1055
1056 /**
1057 * Returns the current ringtone mode.
1058 *
1059 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1060 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1061 * @see #setRingerMode(int)
1062 */
1063 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001064 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001066 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001068 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 }
1070 }
1071
1072 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001073 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1074 *
1075 * @return true if the incoming phone call ringtone is configured to gradually increase its
1076 * volume, false otherwise.
1077 */
1078 public boolean isRampingRingerEnabled() {
1079 return Settings.System.getInt(getContext().getContentResolver(),
1080 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1081 }
1082
1083 /**
1084 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1085 *
1086 * @see #isRampingRingerEnabled()
1087 * @hide
1088 */
1089 @TestApi
1090 public void setRampingRingerEnabled(boolean enabled) {
1091 Settings.System.putInt(getContext().getContentResolver(),
1092 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1093 }
1094
1095 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001096 * Checks valid ringer mode values.
1097 *
1098 * @return true if the ringer mode indicated is valid, false otherwise.
1099 *
1100 * @see #setRingerMode(int)
1101 * @hide
1102 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001103 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001104 public static boolean isValidRingerMode(int ringerMode) {
1105 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1106 return false;
1107 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001108 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001109 try {
1110 return service.isValidRingerMode(ringerMode);
1111 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001112 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001113 }
Eric Laurent72668b22011-07-19 16:04:27 -07001114 }
1115
1116 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 * Returns the maximum volume index for a particular stream.
1118 *
1119 * @param streamType The stream type whose maximum volume index is returned.
1120 * @return The maximum valid volume index for the stream.
1121 * @see #getStreamVolume(int)
1122 */
1123 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001124 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001126 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001128 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 }
1130 }
1131
1132 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001133 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001134 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1135 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1136 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1137 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1138 * @return The minimum valid volume index for the stream.
1139 * @see #getStreamVolume(int)
1140 */
1141 public int getStreamMinVolume(int streamType) {
1142 if (!isPublicStreamType(streamType)) {
1143 throw new IllegalArgumentException("Invalid stream type " + streamType);
1144 }
1145 return getStreamMinVolumeInt(streamType);
1146 }
1147
1148 /**
1149 * @hide
1150 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001151 * @param streamType The stream type whose minimum volume index is returned.
1152 * @return The minimum valid volume index for the stream.
1153 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001154 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001155 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001156 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001157 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001158 try {
1159 return service.getStreamMinVolume(streamType);
1160 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001161 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001162 }
1163 }
1164
1165 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 * Returns the current volume index for a particular stream.
1167 *
1168 * @param streamType The stream type whose volume index is returned.
1169 * @return The current volume index for the stream.
1170 * @see #getStreamMaxVolume(int)
1171 * @see #setStreamVolume(int, int, int)
1172 */
1173 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001174 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001176 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001178 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 }
1180 }
1181
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001182 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1183 private static final float VOLUME_MIN_DB = -758.0f;
1184
1185 /** @hide */
1186 @IntDef(flag = false, prefix = "STREAM", value = {
1187 STREAM_VOICE_CALL,
1188 STREAM_SYSTEM,
1189 STREAM_RING,
1190 STREAM_MUSIC,
1191 STREAM_ALARM,
1192 STREAM_NOTIFICATION,
1193 STREAM_DTMF,
1194 STREAM_ACCESSIBILITY }
1195 )
1196 @Retention(RetentionPolicy.SOURCE)
1197 public @interface PublicStreamTypes {}
1198
1199 /**
1200 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1201 * the given type of audio output device.
1202 * @param streamType stream type for which the volume is queried.
1203 * @param index the volume index for which the volume is queried. The index value must be
1204 * between the minimum and maximum index values for the given stream type (see
1205 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1206 * @param deviceType the type of audio output device for which volume is queried.
1207 * @return a volume expressed in dB.
1208 * A negative value indicates the audio signal is attenuated. A typical maximum value
1209 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1210 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1211 */
1212 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1213 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1214 if (!isPublicStreamType(streamType)) {
1215 throw new IllegalArgumentException("Invalid stream type " + streamType);
1216 }
1217 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1218 throw new IllegalArgumentException("Invalid stream volume index " + index);
1219 }
1220 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1221 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1222 }
1223 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1224 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1225 if (gain <= VOLUME_MIN_DB) {
1226 return Float.NEGATIVE_INFINITY;
1227 } else {
1228 return gain;
1229 }
1230 }
1231
Jean-Michel Trivi283a4c72022-09-28 21:46:51 +00001232 /**
1233 * @hide
1234 * Checks whether a stream type is part of the public SDK
1235 * @param streamType
1236 * @return true if the stream type is available in SDK
1237 */
1238 public static boolean isPublicStreamType(int streamType) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001239 switch (streamType) {
1240 case STREAM_VOICE_CALL:
1241 case STREAM_SYSTEM:
1242 case STREAM_RING:
1243 case STREAM_MUSIC:
1244 case STREAM_ALARM:
1245 case STREAM_NOTIFICATION:
1246 case STREAM_DTMF:
1247 case STREAM_ACCESSIBILITY:
1248 return true;
1249 default:
1250 return false;
1251 }
1252 }
1253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001255 * Get last audible volume before stream was muted.
1256 *
1257 * @hide
1258 */
wescandee178f8f2021-10-19 20:15:09 +02001259 @SystemApi
1260 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001261 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001262 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001263 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001264 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001265 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001266 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001267 }
1268 }
1269
1270 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001271 * Get the stream type whose volume is driving the UI sounds volume.
1272 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001273 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001274 * @hide
1275 */
John Spurlockee5ad722015-03-03 16:17:21 -05001276 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001277 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001278 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001279 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001280 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001281 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001282 }
1283 }
1284
1285 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 * Sets the ringer mode.
1287 * <p>
1288 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1289 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1290 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001291 * <p>This method has no effect if the device implements a fixed volume policy
1292 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001293 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1294 * unless the app has been granted Do Not Disturb Access.
1295 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1297 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1298 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001299 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 */
1301 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001302 if (!isValidRingerMode(ringerMode)) {
1303 return;
1304 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001305 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001307 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001309 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 }
1311 }
1312
1313 /**
1314 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001315 * <p>This method has no effect if the device implements a fixed volume policy
1316 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001317 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1318 * the app has been granted Do Not Disturb Access.
1319 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 * @param streamType The stream whose volume index should be set.
1321 * @param index The volume index to set. See
1322 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1323 * @param flags One or more flags.
1324 * @see #getStreamMaxVolume(int)
1325 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001326 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001327 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1328 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 */
1330 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001331 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 try {
John Wu4f7e5102021-06-22 17:29:11 +00001333 service.setStreamVolumeWithAttribution(streamType, index, flags,
1334 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001336 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 }
1338 }
1339
1340 /**
François Gaffie9c362102018-09-21 17:43:52 +02001341 * Sets the volume index for a particular {@link AudioAttributes}.
1342 * @param attr The {@link AudioAttributes} whose volume index should be set.
1343 * @param index The volume index to set. See
1344 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1345 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1346 * @param flags One or more flags.
1347 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1348 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1349 * @see #isVolumeFixed()
1350 * @hide
1351 */
1352 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001353 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001354 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1355 Preconditions.checkNotNull(attr, "attr must not be null");
1356 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001357 int groupId = getVolumeGroupIdForAttributes(attr);
1358 setVolumeGroupVolumeIndex(groupId, index, flags);
François Gaffie9c362102018-09-21 17:43:52 +02001359 }
1360
1361 /**
1362 * Returns the current volume index for a particular {@link AudioAttributes}.
1363 *
1364 * @param attr The {@link AudioAttributes} whose volume index is returned.
1365 * @return The current volume index for the stream.
1366 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1367 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1368 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1369 * @hide
1370 */
1371 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001372 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001373 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001374 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1375 Preconditions.checkNotNull(attr, "attr must not be null");
1376 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001377 int groupId = getVolumeGroupIdForAttributes(attr);
1378 return getVolumeGroupVolumeIndex(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001379 }
1380
1381 /**
1382 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1383 *
1384 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1385 * @return The maximum valid volume index for the {@link AudioAttributes}.
1386 * @see #getVolumeIndexForAttributes(AudioAttributes)
1387 * @hide
1388 */
1389 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001390 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001391 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001392 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1393 Preconditions.checkNotNull(attr, "attr must not be null");
1394 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001395 int groupId = getVolumeGroupIdForAttributes(attr);
1396 return getVolumeGroupMaxVolumeIndex(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001397 }
1398
1399 /**
1400 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1401 *
1402 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1403 * @return The minimum valid volume index for the {@link AudioAttributes}.
1404 * @see #getVolumeIndexForAttributes(AudioAttributes)
1405 * @hide
1406 */
1407 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001408 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001409 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001410 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1411 Preconditions.checkNotNull(attr, "attr must not be null");
1412 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001413 int groupId = getVolumeGroupIdForAttributes(attr);
1414 return getVolumeGroupMinVolumeIndex(groupId);
1415 }
1416
1417 /**
1418 * Returns the volume group id associated to the given {@link AudioAttributes}.
1419 *
1420 * @param attributes The {@link AudioAttributes} to consider.
1421 * @return {@link android.media.audiopolicy.AudioVolumeGroup} id supporting the given
1422 * {@link AudioAttributes} if found,
1423 * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
1424 */
1425 public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
1426 Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
1427 return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes,
Eric Laurent00c916c2023-02-03 20:50:06 +01001428 /* fallbackOnDefault= */ true);
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001429 }
1430
1431 /**
1432 * Sets the volume index for a particular group associated to given id.
1433 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1434 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1435 *
1436 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1437 * @param index The volume index to set. See
1438 * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
1439 * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
1440 * @param flags One or more flags.
1441 * @hide
1442 */
1443 @SystemApi
1444 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001445 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001446 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1447 })
1448 public void setVolumeGroupVolumeIndex(int groupId, int index, int flags) {
1449 final IAudioService service = getService();
François Gaffie9c362102018-09-21 17:43:52 +02001450 try {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001451 service.setVolumeGroupVolumeIndex(groupId, index, flags,
1452 getContext().getOpPackageName(), getContext().getAttributionTag());
1453 } catch (RemoteException e) {
1454 throw e.rethrowFromSystemServer();
1455 }
1456 }
1457
1458 /**
1459 * Returns the current volume index for a particular group associated to given id.
1460 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1461 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1462 *
1463 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1464 * @return The current volume index for the stream.
1465 * @hide
1466 */
1467 @SystemApi
1468 @IntRange(from = 0)
1469 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001470 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001471 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1472 })
1473 public int getVolumeGroupVolumeIndex(int groupId) {
1474 final IAudioService service = getService();
1475 try {
1476 return service.getVolumeGroupVolumeIndex(groupId);
1477 } catch (RemoteException e) {
1478 throw e.rethrowFromSystemServer();
1479 }
1480 }
1481
1482 /**
1483 * Returns the maximum volume index for a particular group associated to given id.
1484 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1485 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1486 *
1487 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1488 * @return The maximum valid volume index for the {@link AudioAttributes}.
1489 * @hide
1490 */
1491 @SystemApi
1492 @IntRange(from = 0)
1493 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001494 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001495 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1496 })
1497 public int getVolumeGroupMaxVolumeIndex(int groupId) {
1498 final IAudioService service = getService();
1499 try {
1500 return service.getVolumeGroupMaxVolumeIndex(groupId);
1501 } catch (RemoteException e) {
1502 throw e.rethrowFromSystemServer();
1503 }
1504 }
1505
1506 /**
1507 * Returns the minimum volume index for a particular group associated to given id.
1508 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1509 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1510 *
1511 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1512 * @return The minimum valid volume index for the {@link AudioAttributes}.
1513 * @hide
1514 */
1515 @SystemApi
1516 @IntRange(from = 0)
1517 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001518 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001519 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1520 })
1521 public int getVolumeGroupMinVolumeIndex(int groupId) {
1522 final IAudioService service = getService();
1523 try {
1524 return service.getVolumeGroupMinVolumeIndex(groupId);
1525 } catch (RemoteException e) {
1526 throw e.rethrowFromSystemServer();
1527 }
1528 }
1529
1530 /**
1531 * Adjusts the volume of a particular group associated to given id by one step in a direction.
1532 * <p> If the volume group is associated to a stream type, it fallbacks on
1533 * {@link #adjustStreamVolume(int, int, int)} for compatibility reason.
1534 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1535 * the volume group id supporting the given {@link AudioAttributes}.
1536 *
1537 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1538 * @param direction The direction to adjust the volume. One of
1539 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
1540 * {@link #ADJUST_SAME}.
1541 * @param flags One or more flags.
1542 * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
1543 * is not granted notification policy access.
1544 */
1545 public void adjustVolumeGroupVolume(int groupId, int direction, int flags) {
1546 IAudioService service = getService();
1547 try {
1548 service.adjustVolumeGroupVolume(groupId, direction, flags,
1549 getContext().getOpPackageName());
1550 } catch (RemoteException e) {
1551 throw e.rethrowFromSystemServer();
1552 }
1553 }
1554
1555 /**
1556 * Get last audible volume of the group associated to given id before it was muted.
1557 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1558 * the volume group id supporting the given {@link AudioAttributes}.
1559 *
1560 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1561 * @return current volume if not muted, volume before muted otherwise.
1562 * @hide
1563 */
1564 @SystemApi
1565 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
1566 @IntRange(from = 0)
1567 public int getLastAudibleVolumeGroupVolume(int groupId) {
1568 IAudioService service = getService();
1569 try {
1570 return service.getLastAudibleVolumeGroupVolume(groupId);
1571 } catch (RemoteException e) {
1572 throw e.rethrowFromSystemServer();
1573 }
1574 }
1575
1576 /**
1577 * Returns the current mute state for a particular volume group associated to the given id.
1578 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1579 * the volume group id supporting the given {@link AudioAttributes}.
1580 *
1581 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1582 * @return The mute state for the given {@link android.media.audiopolicy.AudioVolumeGroup} id.
1583 * @see #adjustVolumeGroupVolume(int, int, int)
1584 */
1585 public boolean isVolumeGroupMuted(int groupId) {
1586 IAudioService service = getService();
1587 try {
1588 return service.isVolumeGroupMuted(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001589 } catch (RemoteException e) {
1590 throw e.rethrowFromSystemServer();
1591 }
1592 }
1593
1594 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001595 * Set the system usages to be supported on this device.
1596 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1597 * @hide
1598 */
1599 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001600 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes62812aa2019-12-23 11:40:27 -08001601 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1602 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1603 final IAudioService service = getService();
1604 try {
1605 service.setSupportedSystemUsages(systemUsages);
1606 } catch (RemoteException e) {
1607 throw e.rethrowFromSystemServer();
1608 }
1609 }
1610
1611 /**
1612 * Get the system usages supported on this device.
1613 * @return array of supported system usages {@link AttributeSystemUsage}
1614 * @hide
1615 */
1616 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001617 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes62812aa2019-12-23 11:40:27 -08001618 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1619 final IAudioService service = getService();
1620 try {
1621 return service.getSupportedSystemUsages();
1622 } catch (RemoteException e) {
1623 throw e.rethrowFromSystemServer();
1624 }
1625 }
1626
1627 /**
RoboErik4197cb62015-01-21 15:45:32 -08001628 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001630 * Do not use. This method has been deprecated and is now a no-op.
1631 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 *
1633 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001634 * @param state The required solo state: true for solo ON, false for solo
1635 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001636 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001637 * @deprecated Do not use. If you need exclusive audio playback use
1638 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 */
RoboErik4197cb62015-01-21 15:45:32 -08001640 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001642 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 }
1644
1645 /**
1646 * Mute or unmute an audio stream.
1647 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001648 * This method should only be used by applications that replace the
1649 * platform-wide management of audio settings or the main telephony
1650 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001652 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001653 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001654 * <p>
1655 * This method was deprecated in API level 22. Prior to API level 22 this
1656 * method had significantly different behavior and should be used carefully.
1657 * The following applies only to pre-22 platforms:
1658 * <ul>
1659 * <li>The mute command is protected against client process death: if a
1660 * process with an active mute request on a stream dies, this stream will be
1661 * unmuted automatically.</li>
1662 * <li>The mute requests for a given stream are cumulative: the AudioManager
1663 * can receive several mute requests from one or more clients and the stream
1664 * will be unmuted only when the same number of unmute requests are
1665 * received.</li>
1666 * <li>For a better user experience, applications MUST unmute a muted stream
1667 * in onPause() and mute is again in onResume() if appropriate.</li>
1668 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 *
1670 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001671 * @param state The required mute state: true for mute ON, false for mute
1672 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001673 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001674 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1675 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 */
RoboErik4197cb62015-01-21 15:45:32 -08001677 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001679 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1680 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1681 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1682 adjustSuggestedStreamVolume(direction, streamType, 0);
1683 } else {
1684 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 }
1686 }
1687
1688 /**
RoboErik4197cb62015-01-21 15:45:32 -08001689 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001690 *
RoboErik4197cb62015-01-21 15:45:32 -08001691 * @param streamType The stream to get mute state for.
1692 * @return The mute state for the given stream.
1693 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001694 */
1695 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001696 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001697 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001698 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001699 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001700 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001701 }
1702 }
1703
1704 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001705 * get master mute state.
1706 *
1707 * @hide
1708 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001709 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001710 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001711 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001712 try {
1713 return service.isMasterMute();
1714 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001715 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001716 }
1717 }
1718
1719 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001720 * forces the stream controlled by hard volume keys
1721 * specifying streamType == -1 releases control to the
1722 * logic.
1723 *
1724 * @hide
1725 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001726 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001727 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001728 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001729 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001730 try {
1731 service.forceVolumeControlStream(streamType, mICallBack);
1732 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001733 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001734 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001735 }
1736
1737 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 * Returns whether a particular type should vibrate according to user
1739 * settings and the current ringer mode.
1740 * <p>
1741 * This shouldn't be needed by most clients that use notifications to
1742 * vibrate. The notification manager will not vibrate if the policy doesn't
1743 * allow it, so the client should always set a vibrate pattern and let the
1744 * notification manager control whether or not to actually vibrate.
1745 *
1746 * @param vibrateType The type of vibrate. One of
1747 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1748 * {@link #VIBRATE_TYPE_RINGER}.
1749 * @return Whether the type should vibrate at the instant this method is
1750 * called.
1751 * @see #setVibrateSetting(int, int)
1752 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001753 * @deprecated Applications should maintain their own vibrate policy based on
1754 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 */
1756 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001757 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 try {
1759 return service.shouldVibrate(vibrateType);
1760 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001761 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 }
1763 }
1764
1765 /**
1766 * Returns whether the user's vibrate setting for a vibrate type.
1767 * <p>
1768 * This shouldn't be needed by most clients that want to vibrate, instead
1769 * see {@link #shouldVibrate(int)}.
1770 *
1771 * @param vibrateType The type of vibrate. One of
1772 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1773 * {@link #VIBRATE_TYPE_RINGER}.
1774 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1775 * {@link #VIBRATE_SETTING_OFF}, or
1776 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1777 * @see #setVibrateSetting(int, int)
1778 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001779 * @deprecated Applications should maintain their own vibrate policy based on
1780 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 */
1782 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001783 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 try {
1785 return service.getVibrateSetting(vibrateType);
1786 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001787 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 }
1789 }
1790
1791 /**
1792 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001793 * <p>
1794 * This method should only be used by applications that replace the platform-wide
1795 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 *
1797 * @param vibrateType The type of vibrate. One of
1798 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1799 * {@link #VIBRATE_TYPE_RINGER}.
1800 * @param vibrateSetting The vibrate setting, one of
1801 * {@link #VIBRATE_SETTING_ON},
1802 * {@link #VIBRATE_SETTING_OFF}, or
1803 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1804 * @see #getVibrateSetting(int)
1805 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001806 * @deprecated Applications should maintain their own vibrate policy based on
1807 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 */
1809 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001810 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 try {
1812 service.setVibrateSetting(vibrateType, vibrateSetting);
1813 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001814 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
1816 }
1817
1818 /**
1819 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001820 * <p>
1821 * This method should only be used by applications that replace the platform-wide
1822 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 *
1824 * @param on set <var>true</var> to turn on speakerphone;
1825 * <var>false</var> to turn it off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001826 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or
1827 * {@link AudioManager#clearCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001829 @Deprecated public void setSpeakerphoneOn(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001830 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001831 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001832 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001833 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001834 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001835 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
1837
1838 /**
1839 * Checks whether the speakerphone is on or off.
1840 *
1841 * @return true if speakerphone is on, false if it's off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001842 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001844 @Deprecated public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001845 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001846 try {
1847 return service.isSpeakerphoneOn();
1848 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001849 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 }
1852
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001853 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001854 * 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 -07001855 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001856 *
1857 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1858 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001859 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001860 * <ul>
1861 * <li> for each track independently, see
1862 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1863 * <li> application-wide at runtime, with this method </li>
1864 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1865 * manifest. </li>
1866 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001867 * The most restrictive policy is always applied.
1868 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001869 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001870 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001871 *
1872 * @param capturePolicy one of
1873 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1874 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1875 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001876 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001877 */
1878 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001879 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001880 final IAudioService service = getService();
1881 try {
1882 int result = service.setAllowedCapturePolicy(capturePolicy);
1883 if (result != AudioSystem.AUDIO_STATUS_OK) {
1884 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1885 return;
1886 }
1887 } catch (RemoteException e) {
1888 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001889 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001890 }
1891
Kevin Rocard019f60d2019-04-09 16:25:26 -07001892 /**
1893 * Return the capture policy.
1894 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1895 * the default if it was not called.
1896 */
1897 @AudioAttributes.CapturePolicy
1898 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001899 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1900 try {
1901 result = getService().getAllowedCapturePolicy();
1902 } catch (RemoteException e) {
1903 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1904 }
1905 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001906 }
1907
Eric Laurent3def1ee2010-03-17 23:26:26 -07001908 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001909 // Audio Product Strategy routing
1910
1911 /**
1912 * @hide
1913 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1914 * this audio strategy. Note that the device may not be available at the time the preferred
1915 * device is set, but it will be used once made available.
1916 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1917 * this preference for this strategy.</p>
1918 * @param strategy the audio strategy whose routing will be affected
1919 * @param device the audio device to route to when available
1920 * @return true if the operation was successful, false otherwise
1921 */
1922 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001923 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001924 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001925 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001926 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001927 }
1928
1929 /**
1930 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001931 * Removes the preferred audio device(s) previously set with
1932 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1933 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001934 * @param strategy the audio strategy whose routing will be affected
1935 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1936 * device set for example)
1937 */
1938 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001939 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001940 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1941 Objects.requireNonNull(strategy);
1942 try {
1943 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001944 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001945 return status == AudioSystem.SUCCESS;
1946 } catch (RemoteException e) {
1947 throw e.rethrowFromSystemServer();
1948 }
1949 }
1950
1951 /**
1952 * @hide
1953 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001954 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1955 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1956 * @param strategy the strategy to query
1957 * @return the preferred device for that strategy, if multiple devices are set as preferred
1958 * devices, the first one in the list will be returned. Null will be returned if none was
1959 * ever set or if the strategy is invalid
1960 */
1961 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001962 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001963 @Nullable
1964 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1965 @NonNull AudioProductStrategy strategy) {
1966 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1967 return devices.isEmpty() ? null : devices.get(0);
1968 }
1969
1970 /**
1971 * @hide
1972 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1973 * this audio strategy. Note that the devices may not be available at the time the preferred
1974 * devices is set, but it will be used once made available.
1975 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1976 * this preference for this strategy.</p>
1977 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1978 * devices used simultaneously to output the same audio signal.
1979 * @param strategy the audio strategy whose routing will be affected
1980 * @param devices a non-empty list of the audio devices to route to when available
1981 * @return true if the operation was successful, false otherwise
1982 */
1983 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001984 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001985 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1986 @NonNull List<AudioDeviceAttributes> devices) {
1987 Objects.requireNonNull(strategy);
1988 Objects.requireNonNull(devices);
1989 if (devices.isEmpty()) {
1990 throw new IllegalArgumentException(
1991 "Tried to set preferred devices for strategy with a empty list");
1992 }
1993 for (AudioDeviceAttributes device : devices) {
1994 Objects.requireNonNull(device);
1995 }
1996 try {
1997 final int status =
1998 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1999 return status == AudioSystem.SUCCESS;
2000 } catch (RemoteException e) {
2001 throw e.rethrowFromSystemServer();
2002 }
2003 }
2004
2005 /**
2006 * @hide
2007 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002008 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07002009 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002010 * @param strategy the strategy to query
Paul Wang8ee29602022-12-22 03:40:19 +00002011 * @return list of the preferred devices for that strategy
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002012 */
2013 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002014 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002015 @NonNull
2016 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002017 @NonNull AudioProductStrategy strategy) {
2018 Objects.requireNonNull(strategy);
2019 try {
jiabinf40141d2020-08-07 17:27:48 -07002020 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002021 } catch (RemoteException e) {
2022 throw e.rethrowFromSystemServer();
2023 }
2024 }
2025
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002026 /**
2027 * @hide
Paul Wangee4774a2022-08-23 09:41:03 +00002028 * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by
2029 * this audio strategy.
2030 * <p>Use
2031 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2032 * to cancel setting this preference for this strategy.</p>
2033 * @param strategy the audio strategy whose routing will be affected
2034 * @param device the audio device to not route to when available
2035 * @return true if the operation was successful, false otherwise
2036 */
2037 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002038 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002039 public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2040 @NonNull AudioDeviceAttributes device) {
2041 Objects.requireNonNull(strategy);
2042 Objects.requireNonNull(device);
2043 try {
2044 final int status =
2045 getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2046 return status == AudioSystem.SUCCESS;
2047 } catch (RemoteException e) {
2048 throw e.rethrowFromSystemServer();
2049 }
2050 }
2051
2052 /**
2053 * @hide
2054 * Removes the audio device(s) from the non-default device list previously set with
2055 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2056 * @param strategy the audio strategy whose routing will be affected
2057 * @param device the audio device to remove from the non-default device list
2058 * @return true if the operation was successful, false otherwise (invalid strategy, or no
2059 * device set for example)
2060 */
2061 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002062 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002063 public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2064 @NonNull AudioDeviceAttributes device) {
2065 Objects.requireNonNull(strategy);
2066 Objects.requireNonNull(device);
2067 try {
2068 final int status =
2069 getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2070 return status == AudioSystem.SUCCESS;
2071 } catch (RemoteException e) {
2072 throw e.rethrowFromSystemServer();
2073 }
2074 }
2075
2076 /**
2077 * @hide
2078 * Gets the audio device(s) from the non-default device list previously set with
2079 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2080 * @param strategy the audio strategy to query
2081 * @return list of non-default devices for the strategy
2082 */
2083 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002084 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002085 @NonNull
2086 public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
2087 @NonNull AudioProductStrategy strategy) {
2088 Objects.requireNonNull(strategy);
2089 try {
2090 return getService().getNonDefaultDevicesForStrategy(strategy.getId());
2091 } catch (RemoteException e) {
2092 throw e.rethrowFromSystemServer();
2093 }
2094 }
2095
2096 /**
2097 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002098 * Interface to be notified of changes in the preferred audio device set for a given audio
2099 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08002100 * <p>Note that this listener will only be invoked whenever
2101 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07002102 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08002103 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2104 * preferred device. It will not be invoked directly after registration with
2105 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
2106 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002107 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002108 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
2109 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07002110 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002111 */
2112 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07002113 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002114 public interface OnPreferredDeviceForStrategyChangedListener {
2115 /**
2116 * Called on the listener to indicate that the preferred audio device for the given
2117 * strategy has changed.
2118 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2119 * @param device <code>null</code> if the preferred device was removed, or the newly set
2120 * preferred audio device
2121 */
2122 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002123 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002124 }
2125
2126 /**
2127 * @hide
jiabinf40141d2020-08-07 17:27:48 -07002128 * Interface to be notified of changes in the preferred audio devices set for a given audio
2129 * strategy.
2130 * <p>Note that this listener will only be invoked whenever
Paul Wangee4774a2022-08-23 09:41:03 +00002131 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2132 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2133 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2134 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2135 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
jiabinf40141d2020-08-07 17:27:48 -07002136 * preferred device(s). It will not be invoked directly after registration with
2137 * {@link #addOnPreferredDevicesForStrategyChangedListener(
2138 * Executor, OnPreferredDevicesForStrategyChangedListener)}
2139 * to indicate which strategies had preferred devices at the time of registration.</p>
2140 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2141 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
2142 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07002143 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
2144 */
2145 @SystemApi
2146 public interface OnPreferredDevicesForStrategyChangedListener {
2147 /**
2148 * Called on the listener to indicate that the preferred audio devices for the given
2149 * strategy has changed.
2150 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2151 * @param devices a list of newly set preferred audio devices
2152 */
2153 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2154 @NonNull List<AudioDeviceAttributes> devices);
2155 }
2156
2157 /**
2158 * @hide
2159 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2160 * @param executor
2161 * @param listener
2162 * @throws SecurityException if the caller doesn't hold the required permission
2163 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
2164 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2165 */
2166 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002167 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002168 @Deprecated
2169 public void addOnPreferredDeviceForStrategyChangedListener(
2170 @NonNull @CallbackExecutor Executor executor,
2171 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
2172 throws SecurityException {
2173 // No-op, the method is deprecated.
2174 }
2175
2176 /**
2177 * @hide
2178 * Removes a previously added listener of changes to the strategy-preferred audio device.
2179 * @param listener
2180 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
2181 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2182 */
2183 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002184 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002185 @Deprecated
2186 public void removeOnPreferredDeviceForStrategyChangedListener(
2187 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
2188 // No-op, the method is deprecated.
2189 }
2190
2191 /**
2192 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002193 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2194 * @param executor
2195 * @param listener
2196 * @throws SecurityException if the caller doesn't hold the required permission
2197 */
2198 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002199 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002200 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002201 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07002202 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002203 throws SecurityException {
2204 Objects.requireNonNull(executor);
2205 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002206 mPrefDevListenerMgr.addListener(
2207 executor, listener, "addOnPreferredDevicesForStrategyChangedListener",
2208 () -> new StrategyPreferredDevicesDispatcherStub());
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002209 }
2210
2211 /**
2212 * @hide
2213 * Removes a previously added listener of changes to the strategy-preferred audio device.
2214 * @param listener
2215 */
2216 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002217 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002218 public void removeOnPreferredDevicesForStrategyChangedListener(
2219 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002220 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002221 mPrefDevListenerMgr.removeListener(
2222 listener, "removeOnPreferredDevicesForStrategyChangedListener");
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002223 }
2224
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002225 /**
Paul Wangee4774a2022-08-23 09:41:03 +00002226 * @hide
2227 * Interface to be notified of changes in the non-default audio devices set for a given audio
2228 * strategy.
2229 * <p>Note that this listener will only be invoked whenever
2230 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2231 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2232 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2233 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2234 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2235 * non-default device(s). It will not be invoked directly after registration with
2236 * {@link #addOnNonDefaultDevicesForStrategyChangedListener(
2237 * Executor, OnNonDefaultDevicesForStrategyChangedListener)}
2238 * to indicate which strategies had preferred devices at the time of registration.</p>
2239 * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2240 * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2241 */
2242 @SystemApi
2243 public interface OnNonDefaultDevicesForStrategyChangedListener {
2244 /**
2245 * Called on the listener to indicate that the non-default audio devices for the given
2246 * strategy has changed.
2247 * @param strategy the {@link AudioProductStrategy} whose non-default device changed
2248 * @param devices a list of newly set non-default audio devices
2249 */
2250 void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2251 @NonNull List<AudioDeviceAttributes> devices);
2252 }
2253
2254 /**
2255 * @hide
2256 * Adds a listener for being notified of changes to the non-default audio devices for
2257 * strategies.
2258 * @param executor
2259 * @param listener
2260 * @throws SecurityException if the caller doesn't hold the required permission
2261 */
2262 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002263 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002264 public void addOnNonDefaultDevicesForStrategyChangedListener(
2265 @NonNull @CallbackExecutor Executor executor,
2266 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
2267 throws SecurityException {
2268 Objects.requireNonNull(executor);
2269 Objects.requireNonNull(listener);
2270
2271 mNonDefDevListenerMgr.addListener(
2272 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener",
2273 () -> new StrategyNonDefaultDevicesDispatcherStub());
2274 }
2275
2276 /**
2277 * @hide
2278 * Removes a previously added listener of changes to the non-default audio device for
2279 * strategies.
2280 * @param listener
2281 */
2282 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002283 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002284 public void removeOnNonDefaultDevicesForStrategyChangedListener(
2285 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
2286 Objects.requireNonNull(listener);
2287 mNonDefDevListenerMgr.removeListener(
2288 listener, "removeOnNonDefaultDevicesForStrategyChangedListener");
2289 }
2290
2291 /**
Paul Wang8ee29602022-12-22 03:40:19 +00002292 * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the
2293 * StrategyPreferredDevicesDispatcherStub
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002294 */
Paul Wang8ee29602022-12-22 03:40:19 +00002295 private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener>
2296 mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002297
Paul Wangee4774a2022-08-23 09:41:03 +00002298 /**
2299 * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the
2300 * StrategyNonDefaultDevicesDispatcherStub
2301 */
2302 private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener>
2303 mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager();
2304
jiabinf40141d2020-08-07 17:27:48 -07002305 private final class StrategyPreferredDevicesDispatcherStub
Paul Wang8ee29602022-12-22 03:40:19 +00002306 extends IStrategyPreferredDevicesDispatcher.Stub
2307 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002308
2309 @Override
jiabinf40141d2020-08-07 17:27:48 -07002310 public void dispatchPrefDevicesChanged(int strategyId,
2311 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002312 final AudioProductStrategy strategy =
2313 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
Paul Wang8ee29602022-12-22 03:40:19 +00002314
2315 mPrefDevListenerMgr.callListeners(
2316 (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices));
2317 }
2318
2319 @Override
2320 public void register(boolean register) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002321 try {
Paul Wang8ee29602022-12-22 03:40:19 +00002322 if (register) {
2323 getService().registerStrategyPreferredDevicesDispatcher(this);
2324 } else {
2325 getService().unregisterStrategyPreferredDevicesDispatcher(this);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002326 }
Paul Wang8ee29602022-12-22 03:40:19 +00002327 } catch (RemoteException e) {
2328 e.rethrowFromSystemServer();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002329 }
2330 }
2331 }
2332
Paul Wangee4774a2022-08-23 09:41:03 +00002333 private final class StrategyNonDefaultDevicesDispatcherStub
2334 extends IStrategyNonDefaultDevicesDispatcher.Stub
2335 implements CallbackUtil.DispatcherStub {
2336
2337 @Override
2338 public void dispatchNonDefDevicesChanged(int strategyId,
2339 @NonNull List<AudioDeviceAttributes> devices) {
2340 final AudioProductStrategy strategy =
2341 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2342
2343 mNonDefDevListenerMgr.callListeners(
2344 (listener) -> listener.onNonDefaultDevicesForStrategyChanged(
2345 strategy, devices));
2346 }
2347
2348 @Override
2349 public void register(boolean register) {
2350 try {
2351 if (register) {
2352 getService().registerStrategyNonDefaultDevicesDispatcher(this);
2353 } else {
2354 getService().unregisterStrategyNonDefaultDevicesDispatcher(this);
2355 }
2356 } catch (RemoteException e) {
2357 e.rethrowFromSystemServer();
2358 }
2359 }
2360 }
2361
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002362 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002363 // Audio Capture Preset routing
2364
2365 /**
2366 * @hide
2367 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2368 * this capture preset. Note that the device may not be available at the time the preferred
2369 * device is set, but it will be used once made available.
2370 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2371 * for this capture preset.</p>
2372 * @param capturePreset the audio capture preset whose routing will be affected
2373 * @param device the audio device to route to when available
2374 * @return true if the operation was successful, false otherwise
2375 */
2376 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002377 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002378 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002379 @NonNull AudioDeviceAttributes device) {
2380 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2381 }
2382
2383 /**
2384 * @hide
2385 * Remove all the preferred audio devices previously set
2386 * @param capturePreset the audio capture preset whose routing will be affected
2387 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2388 * device set for example)
2389 */
2390 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002391 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002392 public boolean clearPreferredDevicesForCapturePreset(
2393 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002394 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2395 return false;
2396 }
2397 try {
2398 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2399 return status == AudioSystem.SUCCESS;
2400 } catch (RemoteException e) {
2401 throw e.rethrowFromSystemServer();
2402 }
2403 }
2404
2405 /**
2406 * @hide
2407 * Return the preferred devices for an audio capture preset, previously set with
2408 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2409 * @param capturePreset the capture preset to query
2410 * @return a list that contains preferred devices for that capture preset.
2411 */
2412 @NonNull
2413 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002414 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002415 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2416 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002417 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2418 return new ArrayList<AudioDeviceAttributes>();
2419 }
2420 try {
2421 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2422 } catch (RemoteException e) {
2423 throw e.rethrowFromSystemServer();
2424 }
2425 }
2426
2427 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002428 @MediaRecorder.SystemSource int capturePreset,
2429 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002430 Objects.requireNonNull(devices);
2431 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2432 return false;
2433 }
2434 if (devices.size() != 1) {
2435 throw new IllegalArgumentException(
2436 "Only support setting one preferred devices for capture preset");
2437 }
2438 for (AudioDeviceAttributes device : devices) {
2439 Objects.requireNonNull(device);
2440 }
2441 try {
2442 final int status =
2443 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2444 return status == AudioSystem.SUCCESS;
2445 } catch (RemoteException e) {
2446 throw e.rethrowFromSystemServer();
2447 }
2448 }
2449
2450 /**
2451 * @hide
2452 * Interface to be notified of changes in the preferred audio devices set for a given capture
2453 * preset.
2454 * <p>Note that this listener will only be invoked whenever
2455 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2456 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2457 * preferred device. It will not be invoked directly after registration with
2458 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2459 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2460 * to indicate which strategies had preferred devices at the time of registration.</p>
2461 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2462 * @see #clearPreferredDevicesForCapturePreset(int)
2463 * @see #getPreferredDevicesForCapturePreset(int)
2464 */
2465 @SystemApi
2466 public interface OnPreferredDevicesForCapturePresetChangedListener {
2467 /**
2468 * Called on the listener to indicate that the preferred audio devices for the given
2469 * capture preset has changed.
2470 * @param capturePreset the capture preset whose preferred device changed
2471 * @param devices a list of newly set preferred audio devices
2472 */
2473 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002474 @MediaRecorder.SystemSource int capturePreset,
2475 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002476 }
2477
2478 /**
2479 * @hide
2480 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2481 * @param executor
2482 * @param listener
2483 * @throws SecurityException if the caller doesn't hold the required permission
2484 */
2485 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002486 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jiabin Huangb55305f2020-09-03 17:54:16 +00002487 public void addOnPreferredDevicesForCapturePresetChangedListener(
2488 @NonNull @CallbackExecutor Executor executor,
2489 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2490 throws SecurityException {
2491 Objects.requireNonNull(executor);
2492 Objects.requireNonNull(listener);
2493 int status = addOnDevRoleForCapturePresetChangedListener(
2494 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2495 if (status == AudioSystem.ERROR) {
2496 // This must not happen
2497 throw new RuntimeException("Unknown error happened");
2498 }
2499 if (status == AudioSystem.BAD_VALUE) {
2500 throw new IllegalArgumentException(
2501 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2502 + "on a previously registered listener");
2503 }
2504 }
2505
2506 /**
2507 * @hide
2508 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2509 * @param listener
2510 */
2511 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002512 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jiabin Huangb55305f2020-09-03 17:54:16 +00002513 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2514 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2515 Objects.requireNonNull(listener);
2516 int status = removeOnDevRoleForCapturePresetChangedListener(
2517 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2518 if (status == AudioSystem.ERROR) {
2519 // This must not happen
2520 throw new RuntimeException("Unknown error happened");
2521 }
2522 if (status == AudioSystem.BAD_VALUE) {
2523 throw new IllegalArgumentException(
2524 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2525 + "on an unregistered listener");
2526 }
2527 }
2528
2529 private <T> int addOnDevRoleForCapturePresetChangedListener(
2530 @NonNull @CallbackExecutor Executor executor,
2531 @NonNull T listener, int deviceRole) {
2532 Objects.requireNonNull(executor);
2533 Objects.requireNonNull(listener);
2534 DevRoleListeners<T> devRoleListeners =
2535 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2536 if (devRoleListeners == null) {
2537 return AudioSystem.ERROR;
2538 }
2539 synchronized (devRoleListeners.mDevRoleListenersLock) {
2540 if (devRoleListeners.hasDevRoleListener(listener)) {
2541 return AudioSystem.BAD_VALUE;
2542 }
2543 // lazy initialization of the list of device role listener
2544 if (devRoleListeners.mListenerInfos == null) {
2545 devRoleListeners.mListenerInfos = new ArrayList<>();
2546 }
2547 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2548 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2549 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2550 // register binder for callbacks
2551 synchronized (mDevRoleForCapturePresetListenersLock) {
2552 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2553 mDeviceRoleListenersStatus |= (1 << deviceRole);
2554 if (deviceRoleListenerStatus != 0) {
2555 // There are already device role changed listeners active.
2556 return AudioSystem.SUCCESS;
2557 }
2558 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2559 mDevicesRoleForCapturePresetDispatcherStub =
2560 new CapturePresetDevicesRoleDispatcherStub();
2561 }
2562 try {
2563 getService().registerCapturePresetDevicesRoleDispatcher(
2564 mDevicesRoleForCapturePresetDispatcherStub);
2565 } catch (RemoteException e) {
2566 throw e.rethrowFromSystemServer();
2567 }
2568 }
2569 }
2570 }
2571 return AudioSystem.SUCCESS;
2572 }
2573
2574 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2575 @NonNull T listener, int deviceRole) {
2576 Objects.requireNonNull(listener);
2577 DevRoleListeners<T> devRoleListeners =
2578 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2579 if (devRoleListeners == null) {
2580 return AudioSystem.ERROR;
2581 }
2582 synchronized (devRoleListeners.mDevRoleListenersLock) {
2583 if (!devRoleListeners.removeDevRoleListener(listener)) {
2584 return AudioSystem.BAD_VALUE;
2585 }
2586 if (devRoleListeners.mListenerInfos.size() == 0) {
2587 // unregister binder for callbacks
2588 synchronized (mDevRoleForCapturePresetListenersLock) {
2589 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2590 if (mDeviceRoleListenersStatus != 0) {
2591 // There are some other device role changed listeners active.
2592 return AudioSystem.SUCCESS;
2593 }
2594 try {
2595 getService().unregisterCapturePresetDevicesRoleDispatcher(
2596 mDevicesRoleForCapturePresetDispatcherStub);
2597 } catch (RemoteException e) {
2598 throw e.rethrowFromSystemServer();
2599 }
2600 }
2601 }
2602 }
2603 return AudioSystem.SUCCESS;
2604 }
2605
Cole Faust7da659b2022-10-15 21:33:29 -07002606 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of(
2607 AudioSystem.DEVICE_ROLE_PREFERRED,
2608 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
Jiabin Huangb55305f2020-09-03 17:54:16 +00002609
2610 private class DevRoleListenerInfo<T> {
2611 final @NonNull Executor mExecutor;
2612 final @NonNull T mListener;
2613 DevRoleListenerInfo(Executor executor, T listener) {
2614 mExecutor = executor;
2615 mListener = listener;
2616 }
2617 }
2618
2619 private class DevRoleListeners<T> {
2620 private final Object mDevRoleListenersLock = new Object();
2621 @GuardedBy("mDevRoleListenersLock")
2622 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2623
2624 @GuardedBy("mDevRoleListenersLock")
2625 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2626 if (mListenerInfos == null) {
2627 return null;
2628 }
2629 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2630 if (listenerInfo.mListener == listener) {
2631 return listenerInfo;
2632 }
2633 }
2634 return null;
2635 }
2636
2637 @GuardedBy("mDevRoleListenersLock")
2638 private boolean hasDevRoleListener(T listener) {
2639 return getDevRoleListenerInfo(listener) != null;
2640 }
2641
2642 @GuardedBy("mDevRoleListenersLock")
2643 private boolean removeDevRoleListener(T listener) {
2644 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2645 if (infoToRemove != null) {
2646 mListenerInfos.remove(infoToRemove);
2647 return true;
2648 }
2649 return false;
2650 }
2651 }
2652
2653 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2654 /**
2655 * Record if there is a listener added for device role change. If there is a listener added for
2656 * a specified device role change, the bit at position `1 << device_role` is set.
2657 */
2658 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2659 private int mDeviceRoleListenersStatus = 0;
2660 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2661 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2662
2663 private final class CapturePresetDevicesRoleDispatcherStub
2664 extends ICapturePresetDevicesRoleDispatcher.Stub {
2665
2666 @Override
2667 public void dispatchDevicesRoleChanged(
2668 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2669 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2670 if (listenersObj == null) {
2671 return;
2672 }
2673 switch (role) {
2674 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2675 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2676 listeners =
2677 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2678 listenersObj;
2679 final ArrayList<DevRoleListenerInfo<
2680 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2681 synchronized (listeners.mDevRoleListenersLock) {
2682 if (listeners.mListenerInfos.isEmpty()) {
2683 return;
2684 }
2685 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2686 OnPreferredDevicesForCapturePresetChangedListener>>)
2687 listeners.mListenerInfos.clone();
2688 }
2689 final long ident = Binder.clearCallingIdentity();
2690 try {
2691 for (DevRoleListenerInfo<
2692 OnPreferredDevicesForCapturePresetChangedListener> info :
2693 prefDevListeners) {
2694 info.mExecutor.execute(() ->
2695 info.mListener.onPreferredDevicesForCapturePresetChanged(
2696 capturePreset, devices));
2697 }
2698 } finally {
2699 Binder.restoreCallingIdentity(ident);
2700 }
2701 } break;
2702 default:
2703 break;
2704 }
2705 }
2706 }
2707
2708 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002709 // Direct playback query
2710
2711 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2712 direct playback not supported. */
2713 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2714 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2715 direct offload playback supported. Compressed offload is a variant of direct playback.
2716 It is the feature that allows audio processing tasks to be done on the Android device but
2717 not on the application processor, instead, it is handled by dedicated hardware such as audio
2718 DSPs. That will allow the application processor to be idle as much as possible, which is
2719 good for power saving. Compressed offload playback supports
2720 {@link AudioTrack.StreamEventCallback} for event notifications. */
2721 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2722 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2723 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2724 direct offload playback supported with gapless transitions. Compressed offload is a variant
2725 of direct playback. It is the feature that allows audio processing tasks to be done on the
2726 Android device but not on the application processor, instead, it is handled by dedicated
2727 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2728 possible, which is good for power saving. Compressed offload playback supports
2729 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2730 indicates the ability to play consecutive audio tracks without an audio silence in
2731 between. */
2732 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2733 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2734 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2735 direct playback supported. This value covers direct playback that is bitstream pass-through
2736 such as compressed pass-through. */
2737 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2738 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2739
2740 /** @hide */
2741 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2742 DIRECT_PLAYBACK_NOT_SUPPORTED,
2743 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2744 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2745 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2746 )
2747 @Retention(RetentionPolicy.SOURCE)
2748 public @interface AudioDirectPlaybackMode {}
2749
2750 /**
2751 * Returns a bitfield representing the different forms of direct playback currently available
2752 * for a given audio format.
2753 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2754 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2755 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2756 * passthrough.
2757 * <p>Checking for direct support can help the app select the representation of audio content
2758 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2759 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2760 * streams, if needed.
2761 * @param format the audio format (codec, sample rate, channels) being checked.
2762 * @param attributes the {@link AudioAttributes} to be used for playback
2763 * @return the direct playback mode available with given format and attributes. The returned
2764 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2765 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2766 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2767 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2768 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2769 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2770 */
2771 @AudioDirectPlaybackMode
2772 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2773 @NonNull AudioAttributes attributes) {
2774 Objects.requireNonNull(format);
2775 Objects.requireNonNull(attributes);
2776 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2777 }
2778
2779 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002780 // Offload query
2781 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002782 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002783 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2784 * is not competing with other software resources. In general, it is supported by dedicated
2785 * hardware, such as audio DSPs.
2786 * <p>Note that this query only provides information about the support of an audio format,
2787 * it does not indicate whether the resources necessary for the offloaded playback are
2788 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002789 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002790 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002791 * @return true if the given audio format can be offloaded.
2792 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002793 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2794 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002795 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002796 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002797 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002798 if (attributes == null) {
2799 throw new NullPointerException("Illegal null AudioAttributes");
2800 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002801 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2802 }
2803
2804 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2805 offload playback not supported */
2806 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2807 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2808 offload playback supported */
2809 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2810 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2811 offload playback supported with gapless transitions */
2812 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2813 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2814
2815 /** @hide */
2816 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2817 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2818 PLAYBACK_OFFLOAD_SUPPORTED,
2819 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2820 )
2821 @Retention(RetentionPolicy.SOURCE)
2822 public @interface AudioOffloadMode {}
2823
2824 /**
2825 * Returns whether offloaded playback of an audio format is supported on the device or not and
2826 * when supported whether gapless transitions are possible or not.
2827 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2828 * is not competing with other software resources. In general, it is supported by dedicated
2829 * hardware, such as audio DSPs.
2830 * <p>Note that this query only provides information about the support of an audio format,
2831 * it does not indicate whether the resources necessary for the offloaded playback are
2832 * available at that instant.
2833 * @param format the audio format (codec, sample rate, channels) being checked.
2834 * @param attributes the {@link AudioAttributes} to be used for playback
2835 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2836 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2837 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2838 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002839 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002840 */
jiabine22f6aa2021-12-10 01:09:02 +00002841 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002842 @AudioOffloadMode
2843 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2844 @NonNull AudioAttributes attributes) {
2845 if (format == null) {
2846 throw new NullPointerException("Illegal null AudioFormat");
2847 }
2848 if (attributes == null) {
2849 throw new NullPointerException("Illegal null AudioAttributes");
2850 }
2851 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002852 }
2853
2854 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002855 // Immersive audio
2856
2857 /**
2858 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002859 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002860 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2861 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002862 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002863 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002864 return new Spatializer(this);
2865 }
2866
2867 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002868 // Bluetooth SCO control
2869 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002870 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002871 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002872 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2873 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2874 *
2875 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002876 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002877 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002878 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002879 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2880 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2881 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002882
2883 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002884 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002885 * connection state has been updated.
2886 * <p>This intent has two extras:
2887 * <ul>
2888 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2889 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2890 * </ul>
2891 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2892 * <ul>
2893 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2894 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2895 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2896 * </ul>
2897 * @see #startBluetoothSco()
2898 */
2899 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2900 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2901 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2902
Eric Laurent3def1ee2010-03-17 23:26:26 -07002903 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002904 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2905 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002906 */
2907 public static final String EXTRA_SCO_AUDIO_STATE =
2908 "android.media.extra.SCO_AUDIO_STATE";
2909
2910 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002911 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2912 * bluetooth SCO connection state.
2913 */
2914 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2915 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2916
2917 /**
2918 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2919 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002920 */
2921 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2922 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002923 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2924 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002925 */
2926 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2927 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002928 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2929 * indicating that the SCO audio channel is being established
2930 */
2931 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2932 /**
2933 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002934 * there was an error trying to obtain the state
2935 */
2936 public static final int SCO_AUDIO_STATE_ERROR = -1;
2937
2938
2939 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002940 * Indicates if current platform supports use of SCO for off call use cases.
2941 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002942 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002943 * feature.
2944 * @return true if bluetooth SCO can be used for audio when not in call
2945 * false otherwise
2946 * @see #startBluetoothSco()
2947 */
2948 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002949 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002950 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2951 }
2952
2953 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002954 * Start bluetooth SCO audio connection.
2955 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002956 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002957 * <p>This method can be used by applications wanting to send and received audio
2958 * to/from a bluetooth SCO headset while the phone is not in call.
2959 * <p>As the SCO connection establishment can take several seconds,
2960 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002961 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002962 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002963 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2964 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2965 * registration. If the state is already CONNECTED, no state change will be received via the
2966 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2967 * so that the connection stays active in case the current initiator stops the connection.
2968 * <p>Unless the connection is already active as described above, the state will always
2969 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2970 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2971 * <p>When finished with the SCO connection or if the establishment fails, the application must
2972 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002973 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2974 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002975 * <ul>
2976 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2977 * <li> the format must be mono </li>
2978 * <li> the sampling must be 16kHz or 8kHz </li>
2979 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002980 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002981 * <ul>
2982 * <li> the format must be mono </li>
2983 * <li> the sampling must be 8kHz </li>
2984 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002985 * <p>Note that the phone application always has the priority on the usage of the SCO
2986 * connection for telephony. If this method is called while the phone is in call
2987 * it will be ignored. Similarly, if a call is received or sent while an application
2988 * is using the SCO connection, the connection will be lost for the application and NOT
2989 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002990 * <p>NOTE: up to and including API version
2991 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2992 * voice call to the bluetooth headset.
2993 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2994 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002995 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002996 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurentf23f1b72022-02-18 10:57:54 +01002997 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002998 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01002999 @Deprecated public void startBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003000 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003001 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07003002 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07003003 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003004 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003005 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003006 }
3007 }
3008
3009 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003010 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07003011 * Start bluetooth SCO audio connection in virtual call mode.
3012 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003013 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent83900752014-05-15 15:14:22 -07003014 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
3015 * Telephony and communication applications (VoIP, Video Chat) should preferably select
3016 * virtual call mode.
3017 * Applications using voice input for search or commands should first try raw audio connection
3018 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
3019 * failure.
3020 * @see #startBluetoothSco()
3021 * @see #stopBluetoothSco()
3022 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
3023 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003024 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07003025 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003026 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07003027 try {
3028 service.startBluetoothScoVirtualCall(mICallBack);
3029 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003030 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07003031 }
3032 }
3033
3034 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07003035 * Stop bluetooth SCO audio connection.
3036 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003037 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003038 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003039 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
3040 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003041 * @see #startBluetoothSco()
Eric Laurentf23f1b72022-02-18 10:57:54 +01003042 * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003043 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003044 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurentf23f1b72022-02-18 10:57:54 +01003045 @Deprecated public void stopBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003046 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003047 try {
3048 service.stopBluetoothSco(mICallBack);
3049 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003050 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003051 }
3052 }
3053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 /**
Eric Laurenta553c252009-07-17 12:17:14 -07003055 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003056 * <p>
3057 * This method should only be used by applications that replace the platform-wide
3058 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 *
Eric Laurenta553c252009-07-17 12:17:14 -07003060 * @param on set <var>true</var> to use bluetooth SCO for communications;
3061 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003062 */
3063 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003064 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003065 try {
3066 service.setBluetoothScoOn(on);
3067 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003068 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07003069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003070 }
3071
3072 /**
Eric Laurenta553c252009-07-17 12:17:14 -07003073 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 *
Eric Laurenta553c252009-07-17 12:17:14 -07003075 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 * false if otherwise
Eric Laurentf23f1b72022-02-18 10:57:54 +01003077 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003078 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01003079 @Deprecated public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003080 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003081 try {
3082 return service.isBluetoothScoOn();
3083 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003084 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07003085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003086 }
3087
3088 /**
Santiago Seifert1d8f6172022-08-25 14:34:44 +00003089 * @deprecated Use {@link MediaRouter#selectRoute} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 */
Eric Laurenta553c252009-07-17 12:17:14 -07003091 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 }
3093
3094 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08003095 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003096 *
Eric Laurentc117bea2017-02-07 11:04:18 -08003097 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07003098 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08003099 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 */
3101 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07003102 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07003103 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3104 return true;
3105 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
3106 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3107 return true;
3108 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
3109 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07003110 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07003111 }
Eric Laurent9656df22016-04-20 16:42:28 -07003112 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113 }
3114
3115 /**
3116 * Sets audio routing to the wired headset on or off.
3117 *
3118 * @param on set <var>true</var> to route audio to/from wired
3119 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07003120 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121 */
Eric Laurenta553c252009-07-17 12:17:14 -07003122 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 }
3124
3125 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07003126 * Checks whether a wired headset is connected or not.
3127 * <p>This is not a valid indication that audio playback is
3128 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07003130 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003131 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08003132 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003133 */
3134 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08003135 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08003136 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08003137 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06003138 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
3139 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
3140 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07003141 return false;
3142 } else {
3143 return true;
3144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 }
3146
3147 /**
3148 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003149 * <p>
3150 * This method should only be used by applications that replace the platform-wide
3151 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 *
3153 * @param on set <var>true</var> to mute the microphone;
3154 * <var>false</var> to turn mute off
3155 */
Kenny Guy70e0c582015-06-30 19:18:28 +01003156 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003157 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04003158 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01003159 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00003160 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04003161 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003162 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04003163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 }
3165
3166 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003167 * @hide
3168 * Sets the microphone from switch mute on or off.
3169 * <p>
3170 * This method should only be used by InputManager to notify
3171 * Audio Subsystem about Microphone Mute switch state.
3172 *
3173 * @param on set <var>true</var> to mute the microphone;
3174 * <var>false</var> to turn mute off
3175 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003176 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003177 public void setMicrophoneMuteFromSwitch(boolean on) {
3178 final IAudioService service = getService();
3179 try {
3180 service.setMicrophoneMuteFromSwitch(on);
3181 } catch (RemoteException e) {
3182 throw e.rethrowFromSystemServer();
3183 }
3184 }
3185
3186 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 * Checks whether the microphone mute is on or off.
3188 *
3189 * @return true if microphone is muted, false if it's not
3190 */
3191 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003192 final IAudioService service = getService();
3193 try {
3194 return service.isMicrophoneMuted();
3195 } catch (RemoteException e) {
3196 throw e.rethrowFromSystemServer();
3197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003198 }
3199
3200 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08003201 * Broadcast Action: microphone muting state changed.
3202 *
3203 * You <em>cannot</em> receive this through components declared
3204 * in manifests, only by explicitly registering for it with
3205 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3206 * Context.registerReceiver()}.
3207 *
3208 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
3209 * microphone is muted.
3210 */
3211 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3212 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
3213 "android.media.action.MICROPHONE_MUTE_CHANGED";
3214
3215 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07003216 * Broadcast Action: speakerphone state changed.
3217 *
3218 * You <em>cannot</em> receive this through components declared
3219 * in manifests, only by explicitly registering for it with
3220 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3221 * Context.registerReceiver()}.
3222 *
3223 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
3224 * speakerphone functionality is enabled or not.
3225 */
3226 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3227 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
3228 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
3229
3230 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003232 * <p>
3233 * The audio mode encompasses audio routing AND the behavior of
3234 * the telephony layer. Therefore this method should only be used by applications that
3235 * replace the platform-wide management of audio settings or the main telephony application.
3236 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
3237 * application when it places a phone call, as it will cause signals from the radio layer
3238 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003240 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 * Informs the HAL about the current audio state so that
3242 * it can route the audio appropriately.
3243 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003244 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003245 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07003247 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003249 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003250 }
3251 }
3252
3253 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01003254 * This change id controls use of audio modes for call audio redirection.
3255 * @hide
3256 */
3257 @ChangeId
3258 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
3259 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
3260
3261 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 * Returns the current audio mode.
3263 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003264 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003266 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003268 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003270 int mode = service.getMode();
3271 int sdk;
3272 try {
3273 sdk = getContext().getApplicationInfo().targetSdkVersion;
3274 } catch (NullPointerException e) {
3275 // some tests don't have a Context
3276 sdk = Build.VERSION.SDK_INT;
3277 }
3278 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3279 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01003280 } else if (mode == MODE_CALL_REDIRECT
3281 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3282 mode = MODE_IN_CALL;
3283 } else if (mode == MODE_COMMUNICATION_REDIRECT
3284 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3285 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003286 }
3287 return mode;
3288 } catch (RemoteException e) {
3289 throw e.rethrowFromSystemServer();
3290 }
3291 }
3292
3293 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003294 * Interface definition of a callback that is notified when the audio mode changes
3295 */
3296 public interface OnModeChangedListener {
3297 /**
3298 * Called on the listener to indicate that the audio mode has changed
3299 *
3300 * @param mode The current audio mode
3301 */
3302 void onModeChanged(@AudioMode int mode);
3303 }
3304
Nate Myren08635fe2021-04-20 12:04:39 -07003305 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003306 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003307 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003308 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3309 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003310
Nate Myren08635fe2021-04-20 12:04:39 -07003311
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003312 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3313 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003314
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003315 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003316 public void register(boolean register) {
3317 try {
3318 if (register) {
3319 getService().registerModeDispatcher(this);
3320 } else {
3321 getService().unregisterModeDispatcher(this);
3322 }
3323 } catch (RemoteException e) {
3324 e.rethrowFromSystemServer();
3325 }
3326 }
Nate Myren08635fe2021-04-20 12:04:39 -07003327
3328 @Override
3329 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003330 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003331 }
3332 }
3333
Nate Myren08635fe2021-04-20 12:04:39 -07003334 /**
3335 * Adds a listener to be notified of changes to the audio mode.
3336 * See {@link #getMode()}
3337 * @param executor
3338 * @param listener
3339 */
3340 public void addOnModeChangedListener(
3341 @NonNull @CallbackExecutor Executor executor,
3342 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003343 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3344 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003345 }
3346
3347 /**
3348 * Removes a previously added listener for changes to audio mode.
3349 * See {@link #getMode()}
3350 * @param listener
3351 */
3352 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003353 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003354 }
3355
3356 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003357 * Indicates if the platform supports a special call screening and call monitoring mode.
3358 * <p>
3359 * When this mode is supported, it is possible to perform call screening and monitoring
3360 * functions while other use cases like music or movie playback are active.
3361 * <p>
3362 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3363 * call screening mode.
3364 * <p>
3365 * If call screening mode is not supported, setting mode to
3366 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3367 * {@link #getMode()}.
3368 * @return true if call screening mode is supported, false otherwise.
3369 */
3370 public boolean isCallScreeningModeSupported() {
3371 final IAudioService service = getService();
3372 try {
3373 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003375 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 }
3377 }
3378
3379 /* modes for setMode/getMode/setRoute/getRoute */
3380 /**
3381 * Audio harware modes.
3382 */
3383 /**
3384 * Invalid audio mode.
3385 */
3386 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3387 /**
3388 * Current audio mode. Used to apply audio routing to current mode.
3389 */
3390 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3391 /**
3392 * Normal audio mode: not ringing and no call established.
3393 */
3394 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3395 /**
3396 * Ringing audio mode. An incoming is being signaled.
3397 */
3398 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3399 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003400 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003401 */
3402 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003403 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003404 * In communication audio mode. An audio/video chat or VoIP call is established.
3405 */
3406 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003407 /**
3408 * Call screening in progress. Call is connected and audio is accessible to call
3409 * screening applications but other audio use cases are still possible.
3410 */
3411 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3412
Eric Laurent1c3408f2021-11-09 12:09:54 +01003413 /**
3414 * A telephony call is established and its audio is being redirected to another device.
3415 */
3416 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3417
3418 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003419 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003420 * device.
3421 */
3422 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3423
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003424 /** @hide */
3425 @IntDef(flag = false, prefix = "MODE_", value = {
3426 MODE_NORMAL,
3427 MODE_RINGTONE,
3428 MODE_IN_CALL,
3429 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003430 MODE_CALL_SCREENING,
3431 MODE_CALL_REDIRECT,
3432 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003433 )
3434 @Retention(RetentionPolicy.SOURCE)
3435 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436
3437 /* Routing bits for setRouting/getRouting API */
3438 /**
3439 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003440 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3441 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 */
Eric Laurenta553c252009-07-17 12:17:14 -07003443 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003445 * Routing audio output to speaker
3446 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3447 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 */
Eric Laurenta553c252009-07-17 12:17:14 -07003449 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003450 /**
3451 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003452 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3453 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003454 */
3455 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3456 /**
3457 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003458 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3459 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 */
Eric Laurenta553c252009-07-17 12:17:14 -07003461 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 /**
3463 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003464 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3465 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 */
Eric Laurenta553c252009-07-17 12:17:14 -07003467 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468 /**
3469 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003470 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3471 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 */
Eric Laurenta553c252009-07-17 12:17:14 -07003473 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 /**
3475 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003476 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3477 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 */
Eric Laurenta553c252009-07-17 12:17:14 -07003479 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003480
3481 /**
3482 * Sets the audio routing for a specified mode
3483 *
3484 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3485 * @param routes bit vector of routes requested, created from one or
3486 * more of ROUTE_xxx types. Set bits indicate that route should be on
3487 * @param mask bit vector of routes to change, created from one or more of
3488 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003489 *
3490 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003491 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003492 */
Eric Laurenta553c252009-07-17 12:17:14 -07003493 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003495 }
3496
3497 /**
3498 * Returns the current audio routing bit vector for a specified mode.
3499 *
3500 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3501 * @return an audio route bit vector that can be compared with ROUTE_xxx
3502 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003503 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3504 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003506 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003508 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 }
3510
3511 /**
3512 * Checks whether any music is active.
3513 *
3514 * @return true if any music tracks are active.
3515 */
3516 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003517 final IAudioService service = getService();
3518 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003519 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003520 } catch (RemoteException e) {
3521 throw e.rethrowFromSystemServer();
3522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 }
3524
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003525 /**
3526 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003527 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3528 * display). Note that BT audio sinks are not considered remote devices.
3529 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3530 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003531 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003532 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003533 final IAudioService service = getService();
3534 try {
3535 return service.isMusicActive(true /*remotely*/);
3536 } catch (RemoteException e) {
3537 throw e.rethrowFromSystemServer();
3538 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003539 }
3540
3541 /**
3542 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003543 * Checks whether the current audio focus is exclusive.
3544 * @return true if the top of the audio focus stack requested focus
3545 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3546 */
3547 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003548 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003549 try {
3550 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3551 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003552 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003553 }
3554 }
3555
3556 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003557 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003558 * An audio session identifier is a system wide unique identifier for a set of audio streams
3559 * (one or more mixed together).
3560 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3561 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3562 * session ID will be applied to the mixed audio content of the players that share the same
3563 * audio session.
3564 * <p>This method can for instance be used when creating one of the
3565 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3566 * or to specify a session for a speech synthesis utterance
3567 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003568 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003569 * system failed to generate a new session, a condition in which audio playback or recording
3570 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003571 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003572 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003573 int session = AudioSystem.newAudioSessionId();
3574 if (session > 0) {
3575 return session;
3576 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003577 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003578 return ERROR;
3579 }
3580 }
3581
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003582 /**
3583 * A special audio session ID to indicate that the audio session ID isn't known and the
3584 * framework should generate a new value. This can be used when building a new
3585 * {@link AudioTrack} instance with
3586 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3587 */
3588 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3589
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 /*
3592 * Sets a generic audio configuration parameter. The use of these parameters
3593 * are platform dependant, see libaudio
3594 *
3595 * ** Temporary interface - DO NOT USE
3596 *
3597 * TODO: Replace with a more generic key:value get/set mechanism
3598 *
3599 * param key name of parameter to set. Must not be null.
3600 * param value value of parameter. Must not be null.
3601 */
3602 /**
3603 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003604 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003605 */
Eric Laurenta553c252009-07-17 12:17:14 -07003606 @Deprecated public void setParameter(String key, String value) {
3607 setParameters(key+"="+value);
3608 }
3609
3610 /**
3611 * Sets a variable number of parameter values to audio hardware.
3612 *
3613 * @param keyValuePairs list of parameters key value pairs in the form:
3614 * key1=value1;key2=value2;...
3615 *
3616 */
3617 public void setParameters(String keyValuePairs) {
3618 AudioSystem.setParameters(keyValuePairs);
3619 }
3620
3621 /**
William Escandeef429b62021-10-15 18:37:40 +02003622 * @hide
3623 */
3624 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003625 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003626 public void setHfpEnabled(boolean enable) {
3627 AudioSystem.setParameters("hfp_enable=" + enable);
3628 }
3629
3630 /**
3631 * @hide
3632 */
3633 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003634 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003635 public void setHfpVolume(int volume) {
3636 AudioSystem.setParameters("hfp_volume=" + volume);
3637 }
3638
3639 /**
3640 * @hide
3641 */
3642 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003643 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003644 public void setHfpSamplingRate(int rate) {
3645 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3646 }
3647
3648 /**
3649 * @hide
3650 */
3651 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003652 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003653 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3654 boolean hasWbsEnabled) {
3655 AudioSystem.setParameters("bt_headset_name=" + name
3656 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3657 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3658 }
3659
3660 /**
3661 * @hide
3662 */
3663 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003664 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003665 public void setA2dpSuspended(boolean enable) {
3666 AudioSystem.setParameters("A2dpSuspended=" + enable);
3667 }
3668
3669 /**
Rahul Sabnis215e5412022-12-21 16:03:07 -08003670 * Suspends the use of LE Audio.
3671 *
3672 * @param enable {@code true} to suspend le audio, {@code false} to unsuspend
3673 *
3674 * @hide
3675 */
3676 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003677 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
Rahul Sabnis215e5412022-12-21 16:03:07 -08003678 public void setLeAudioSuspended(boolean enable) {
3679 AudioSystem.setParameters("LeAudioSuspended=" + enable);
3680 }
3681
3682 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003683 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003684 *
3685 * @param keys list of parameters
3686 * @return list of parameters key value pairs in the form:
3687 * key1=value1;key2=value2;...
3688 */
3689 public String getParameters(String keys) {
3690 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003691 }
3692
3693 /* Sound effect identifiers */
3694 /**
3695 * Keyboard and direction pad click sound
3696 * @see #playSoundEffect(int)
3697 */
3698 public static final int FX_KEY_CLICK = 0;
3699 /**
3700 * Focus has moved up
3701 * @see #playSoundEffect(int)
3702 */
3703 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3704 /**
3705 * Focus has moved down
3706 * @see #playSoundEffect(int)
3707 */
3708 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3709 /**
3710 * Focus has moved left
3711 * @see #playSoundEffect(int)
3712 */
3713 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3714 /**
3715 * Focus has moved right
3716 * @see #playSoundEffect(int)
3717 */
3718 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3719 /**
3720 * IME standard keypress sound
3721 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 */
3723 public static final int FX_KEYPRESS_STANDARD = 5;
3724 /**
3725 * IME spacebar keypress sound
3726 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003727 */
3728 public static final int FX_KEYPRESS_SPACEBAR = 6;
3729 /**
3730 * IME delete keypress sound
3731 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732 */
3733 public static final int FX_KEYPRESS_DELETE = 7;
3734 /**
3735 * IME return_keypress sound
3736 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 */
3738 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003739
3740 /**
3741 * Invalid keypress sound
3742 * @see #playSoundEffect(int)
3743 */
3744 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003745
3746 /**
3747 * Back sound
3748 * @see #playSoundEffect(int)
3749 */
3750 public static final int FX_BACK = 10;
3751
3752 /**
3753 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003754 * <p>
3755 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3756 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003757 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3758 * @see #playSoundEffect(int)
3759 */
3760 public static final int FX_HOME = 11;
3761
3762 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003763 * @hide Navigation repeat sound 1
3764 * <p>
3765 * To be played by the framework when a focus navigation is repeatedly triggered
3766 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003767 * This is currently only used on TV devices.
3768 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3769 * @see #playSoundEffect(int)
3770 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003771 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003772
3773 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003774 * @hide Navigation repeat sound 2
3775 * <p>
3776 * To be played by the framework when a focus navigation is repeatedly triggered
3777 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003778 * This is currently only used on TV devices.
3779 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3780 * @see #playSoundEffect(int)
3781 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003782 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003783
3784 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003785 * @hide Navigation repeat sound 3
3786 * <p>
3787 * To be played by the framework when a focus navigation is repeatedly triggered
3788 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003789 * This is currently only used on TV devices.
3790 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3791 * @see #playSoundEffect(int)
3792 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003793 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003794
3795 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003796 * @hide Navigation repeat sound 4
3797 * <p>
3798 * To be played by the framework when a focus navigation is repeatedly triggered
3799 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003800 * This is currently only used on TV devices.
3801 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3802 * @see #playSoundEffect(int)
3803 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003804 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003806 /**
3807 * @hide Number of sound effects
3808 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003809 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003810 public static final int NUM_SOUND_EFFECTS = 16;
3811
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003812 /** @hide */
3813 @IntDef(prefix = { "FX_" }, value = {
3814 FX_KEY_CLICK,
3815 FX_FOCUS_NAVIGATION_UP,
3816 FX_FOCUS_NAVIGATION_DOWN,
3817 FX_FOCUS_NAVIGATION_LEFT,
3818 FX_FOCUS_NAVIGATION_RIGHT,
3819 FX_KEYPRESS_STANDARD,
3820 FX_KEYPRESS_SPACEBAR,
3821 FX_KEYPRESS_DELETE,
3822 FX_KEYPRESS_RETURN,
3823 FX_KEYPRESS_INVALID,
3824 FX_BACK
3825 })
3826 @Retention(RetentionPolicy.SOURCE)
3827 public @interface SystemSoundEffect {}
3828
Philip Junker7f1fdff2020-12-03 16:10:41 +01003829 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003830 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003831 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003832 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003833
3834 /**
3835 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003836 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3837 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003838 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003839 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003840 switch (n) {
3841 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003842 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003843 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003844 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003845 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003846 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003847 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003848 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003849 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003850 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003851 return -1;
3852 }
3853 }
3854
3855 /**
3856 * @hide
3857 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003858 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003859 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003860 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003861 } catch (RemoteException e) {
3862
3863 }
3864 }
3865
3866 /**
3867 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003868 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003869 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003870 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003871 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003872 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003873 } catch (RemoteException e) {
3874 throw e.rethrowFromSystemServer();
3875 }
3876 }
3877
3878 /**
3879 * @hide
3880 * @param enabled
3881 */
3882 public void setHomeSoundEffectEnabled(boolean enabled) {
3883 try {
3884 getService().setHomeSoundEffectEnabled(enabled);
3885 } catch (RemoteException e) {
3886
3887 }
3888 }
3889
3890 /**
3891 * @hide
3892 * @return true if the home sound effect is enabled
3893 */
3894 public boolean isHomeSoundEffectEnabled() {
3895 try {
3896 return getService().isHomeSoundEffectEnabled();
3897 } catch (RemoteException e) {
3898 throw e.rethrowFromSystemServer();
3899 }
3900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901
3902 /**
3903 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003904 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003905 * NOTE: This version uses the UI settings to determine
3906 * whether sounds are heard or not.
3907 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003908 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003909 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003910 }
3911
3912 /**
3913 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003914 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003915 * @param userId The current user to pull sound settings from
3916 * NOTE: This version uses the UI settings to determine
3917 * whether sounds are heard or not.
3918 * @hide
3919 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003920 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003921 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3922 return;
3923 }
3924
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003925 if (delegateSoundEffectToVdm(effectType)) {
3926 return;
3927 }
3928
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003929 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003931 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003932 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003933 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003934 }
3935 }
3936
3937 /**
3938 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003939 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003940 * @param volume Sound effect volume.
3941 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3942 * 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 -08003943 * NOTE: This version is for applications that have their own
3944 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003945 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003946 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003947 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3948 return;
3949 }
3950
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003951 if (delegateSoundEffectToVdm(effectType)) {
3952 return;
3953 }
3954
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003955 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003956 try {
3957 service.playSoundEffectVolume(effectType, volume);
3958 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003959 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960 }
3961 }
3962
3963 /**
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003964 * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice}
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003965 * configured with custom device policy for audio. If there is such device, request to play
3966 * sound effect is forwarded to {@link VirtualDeviceManager}.
3967 *
3968 * @param effectType - The type of sound effect.
3969 * @return true if the request was forwarded to {@link VirtualDeviceManager} instance,
3970 * false otherwise.
3971 */
3972 private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003973 if (hasCustomPolicyVirtualDeviceContext()) {
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003974 VirtualDeviceManager vdm = getVirtualDeviceManager();
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003975 vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
3976 return true;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003977 }
3978 return false;
3979 }
3980
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003981 private boolean hasCustomPolicyVirtualDeviceContext() {
3982 if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) {
3983 return false;
3984 }
3985
3986 VirtualDeviceManager vdm = getVirtualDeviceManager();
3987 return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO)
3988 != DEVICE_POLICY_DEFAULT;
3989 }
3990
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003991 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003992 * Load Sound effects.
3993 * This method must be called when sound effects are enabled.
3994 */
3995 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003996 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003997 try {
3998 service.loadSoundEffects();
3999 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004000 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004001 }
4002 }
4003
4004 /**
4005 * Unload Sound effects.
4006 * This method can be called to free some memory when
4007 * sound effects are disabled.
4008 */
4009 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004010 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 try {
4012 service.unloadSoundEffects();
4013 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004014 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004015 }
4016 }
4017
Eric Laurent4050c932009-07-08 02:52:14 -07004018 /**
Andy Hung69836952020-03-26 01:00:15 -07004019 * @hide
4020 */
4021 public static String audioFocusToString(int focus) {
4022 switch (focus) {
4023 case AUDIOFOCUS_NONE:
4024 return "AUDIOFOCUS_NONE";
4025 case AUDIOFOCUS_GAIN:
4026 return "AUDIOFOCUS_GAIN";
4027 case AUDIOFOCUS_GAIN_TRANSIENT:
4028 return "AUDIOFOCUS_GAIN_TRANSIENT";
4029 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
4030 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
4031 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
4032 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
4033 case AUDIOFOCUS_LOSS:
4034 return "AUDIOFOCUS_LOSS";
4035 case AUDIOFOCUS_LOSS_TRANSIENT:
4036 return "AUDIOFOCUS_LOSS_TRANSIENT";
4037 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
4038 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
4039 default:
4040 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
4041 }
4042 }
4043
4044 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08004045 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004046 */
4047 public static final int AUDIOFOCUS_NONE = 0;
4048
4049 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004050 * 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 -07004051 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004052 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004053 */
4054 public static final int AUDIOFOCUS_GAIN = 1;
4055 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004056 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
4057 * amount of time. Examples of temporary changes are the playback of driving directions, or an
4058 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004059 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004060 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004061 */
4062 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004063 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004064 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004065 * amount of time, and where it is acceptable for other audio applications to keep playing
4066 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004067 * Examples of temporary changes are the playback of driving directions where playback of music
4068 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004069 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004070 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4071 */
4072 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
4073 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004074 * Used to indicate a temporary request of audio focus, anticipated to last a short
4075 * amount of time, during which no other applications, or system components, should play
4076 * anything. Examples of exclusive and transient audio focus requests are voice
4077 * memo recording and speech recognition, during which the system shouldn't play any
4078 * notifications, and media playback should have paused.
4079 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4080 */
4081 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
4082 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004083 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004084 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004085 */
4086 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
4087 /**
4088 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004089 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004090 */
4091 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
4092 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004093 * 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 -07004094 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
4095 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004096 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004097 */
4098 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
4099 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004100
4101 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004102 * Interface definition for a callback to be invoked when the audio focus of the system is
4103 * updated.
4104 */
4105 public interface OnAudioFocusChangeListener {
4106 /**
4107 * Called on the listener to notify it the audio focus for this listener has been changed.
4108 * The focusChange value indicates whether the focus was gained,
4109 * whether the focus was lost, and whether that loss is transient, or whether the new focus
4110 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004111 * When losing focus, listeners can use the focus change information to decide what
4112 * behavior to adopt when losing focus. A music player could for instance elect to lower
4113 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
4114 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004115 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004116 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004117 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004118 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004119 }
4120
4121 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004122 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
4123 */
4124 private static class FocusRequestInfo {
4125 @NonNull final AudioFocusRequest mRequest;
4126 @Nullable final Handler mHandler;
4127 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
4128 mRequest = afr;
4129 mHandler = handler;
4130 }
4131 }
4132
4133 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004134 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
4135 * to actual listener objects.
4136 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01004137 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004138 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
4139 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004140
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004141 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004142 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004143 }
4144
4145 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004146 * Handler for events (audio focus change, recording config change) coming from the
4147 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004148 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004149 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004150 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004151
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004152 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004153 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004154 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004155 private final static int MSSG_FOCUS_CHANGE = 0;
4156 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004157 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004158
4159 /**
4160 * Helper class to handle the forwarding of audio service events to the appropriate listener
4161 */
4162 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004163 private final Handler mHandler;
4164
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004165 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004166 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004167 if (handler == null) {
4168 if ((looper = Looper.myLooper()) == null) {
4169 looper = Looper.getMainLooper();
4170 }
4171 } else {
4172 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004173 }
4174
4175 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004176 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004177 mHandler = new Handler(looper) {
4178 @Override
4179 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004180 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004181 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004182 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
4183 if (fri != null) {
4184 final OnAudioFocusChangeListener listener =
4185 fri.mRequest.getOnAudioFocusChangeListener();
4186 if (listener != null) {
4187 Log.d(TAG, "dispatching onAudioFocusChange("
4188 + msg.arg1 + ") to " + msg.obj);
4189 listener.onAudioFocusChange(msg.arg1);
4190 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004191 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004192 } break;
4193 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08004194 final RecordConfigChangeCallbackData cbData =
4195 (RecordConfigChangeCallbackData) msg.obj;
4196 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07004197 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004198 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004199 } break;
4200 case MSSG_PLAYBACK_CONFIG_CHANGE: {
4201 final PlaybackConfigChangeCallbackData cbData =
4202 (PlaybackConfigChangeCallbackData) msg.obj;
4203 if (cbData.mCb != null) {
4204 if (DEBUG) {
4205 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
4206 }
4207 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
4208 }
4209 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004210 default:
4211 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004212 }
4213 }
4214 };
4215 } else {
4216 mHandler = null;
4217 }
4218 }
4219
4220 Handler getHandler() {
4221 return mHandler;
4222 }
4223 }
4224
Glenn Kasten30c918c2011-11-10 17:56:41 -08004225 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004226 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004227 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004228 final FocusRequestInfo fri = findFocusRequestInfo(id);
4229 if (fri != null) {
4230 final OnAudioFocusChangeListener listener =
4231 fri.mRequest.getOnAudioFocusChangeListener();
4232 if (listener != null) {
4233 final Handler h = (fri.mHandler == null) ?
4234 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
4235 final Message m = h.obtainMessage(
4236 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
4237 id/*obj*/);
4238 h.sendMessage(m);
4239 }
4240 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004241 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004242
4243 @Override
4244 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
4245 synchronized (mFocusRequestsLock) {
4246 // TODO use generation counter as the key instead
4247 final BlockingFocusResultReceiver focusReceiver =
4248 mFocusRequestsAwaitingResult.remove(clientId);
4249 if (focusReceiver != null) {
4250 focusReceiver.notifyResult(requestResult);
4251 } else {
4252 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
4253 }
4254 }
4255 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004256 };
4257
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004258 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004259 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07004260 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004261 } else {
4262 return new String(this.toString() + l.toString());
4263 }
4264 }
4265
4266 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004267 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004268 * Registers a listener to be called when audio focus changes and keeps track of the associated
4269 * focus request (including Handler to use for the listener).
4270 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004271 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004272 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
4273 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
4274 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
4275 new ServiceEventHandlerDelegate(h).getHandler());
4276 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4277 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004278 }
4279
4280 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004281 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004282 * Causes the specified listener to not be called anymore when focus is gained or lost.
4283 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004284 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004285 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004286 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004287 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004288 }
4289
4290
4291 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004292 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004293 */
4294 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
4295 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004296 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004297 */
4298 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004299 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004300 * A focus change request whose granting is delayed: the request was successful, but the
4301 * requester will only be granted audio focus once the condition that prevented immediate
4302 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004303 * See {@link #requestAudioFocus(AudioFocusRequest)} and
4304 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004305 */
4306 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004307
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004308 /** @hide */
4309 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
4310 AUDIOFOCUS_REQUEST_FAILED,
4311 AUDIOFOCUS_REQUEST_GRANTED,
4312 AUDIOFOCUS_REQUEST_DELAYED }
4313 )
4314 @Retention(RetentionPolicy.SOURCE)
4315 public @interface FocusRequestResult {}
4316
4317 /**
4318 * @hide
4319 * code returned when a synchronous focus request on the client-side is to be blocked
4320 * until the external audio focus policy decides on the response for the client
4321 */
4322 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
4323
4324 /**
4325 * Timeout duration in ms when waiting on an external focus policy for the result for a
4326 * focus request
4327 */
Weilin Xu1017d432022-06-08 00:27:52 +00004328 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004329
4330 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4331
4332 private final Object mFocusRequestsLock = new Object();
4333 /**
4334 * Map of all receivers of focus request results, one per unresolved focus request.
4335 * Receivers are added before sending the request to the external focus policy,
4336 * and are removed either after receiving the result, or after the timeout.
4337 * This variable is lazily initialized.
4338 */
4339 @GuardedBy("mFocusRequestsLock")
4340 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4341
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004342
4343 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004344 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004345 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004346 * @param l the listener to be notified of audio focus changes
4347 * @param streamType the main audio stream type affected by the focus request
4348 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4349 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004350 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004351 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4352 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004353 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4354 * that benefits from the system not playing disruptive sounds like notifications, for
4355 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004356 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004357 * as the playback of a song or a video.
4358 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004359 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004360 */
4361 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004362 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4363 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004364 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004365
4366 try {
4367 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4368 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4369 // AUDIOFOCUS_FLAG_DELAY_OK flag
4370 status = requestAudioFocus(l,
4371 new AudioAttributes.Builder()
4372 .setInternalLegacyStreamType(streamType).build(),
4373 durationHint,
4374 0 /* flags, legacy behavior */);
4375 } catch (IllegalArgumentException e) {
4376 Log.e(TAG, "Audio focus request denied due to ", e);
4377 }
4378
4379 return status;
4380 }
4381
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004382 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004383 /**
4384 * @hide
4385 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4386 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4387 * the system is in a state where focus cannot change, but be granted focus later when
4388 * this condition ends.
4389 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004390 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004391 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004392 /**
4393 * @hide
4394 * Use this flag when requesting audio focus to indicate that the requester
4395 * will pause its media playback (if applicable) when losing audio focus with
4396 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4397 * <br>On some platforms, the ducking may be handled without the application being aware of it
4398 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4399 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4400 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4401 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004402 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004403 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4404 /**
4405 * @hide
4406 * Use this flag to lock audio focus so granting is temporarily disabled.
4407 * <br>This flag can only be used by owners of a registered
4408 * {@link android.media.audiopolicy.AudioPolicy} in
4409 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4410 */
4411 @SystemApi
4412 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004413
4414 /**
4415 * @hide
4416 * flag set on test API calls,
4417 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004418 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004419 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004420 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004421 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4422 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004423 /** @hide */
4424 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004425 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004426
4427 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004428 * Request audio focus.
4429 * See the {@link AudioFocusRequest} for information about the options available to configure
4430 * your request, and notification of focus gain and loss.
4431 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4432 * requested.
4433 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4434 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4435 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4436 * is requested without building the {@link AudioFocusRequest} with
4437 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4438 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004439 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004440 */
4441 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004442 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004443 }
4444
4445 /**
4446 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4447 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4448 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4449 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4450 * @throws IllegalArgumentException if passed a null argument
4451 */
4452 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4453 if (focusRequest == null) {
4454 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4455 }
4456 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4457 focusRequest.getAudioAttributes());
4458 }
4459
4460 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004461 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004462 * Request audio focus.
4463 * Send a request to obtain the audio focus. This method differs from
4464 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4465 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004466 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4467 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4468 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4469 * requesting audio focus.
4470 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4471 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4472 * for the playback of driving directions, or notifications sounds.
4473 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4474 * the previous focus owner to keep playing if it ducks its audio output.
4475 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4476 * that benefits from the system not playing disruptive sounds like notifications, for
4477 * usecases such as voice memo recording, or speech recognition.
4478 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4479 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004480 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4481 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004482 * <br>Use 0 when not using any flags for the request, which behaves like
4483 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4484 * focus is granted immediately, or the grant request fails because the system is in a
4485 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004486 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4487 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4488 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4489 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4490 * @throws IllegalArgumentException
4491 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004492 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004493 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004494 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004495 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004496 int durationHint,
4497 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004498 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4499 throw new IllegalArgumentException("Invalid flags 0x"
4500 + Integer.toHexString(flags).toUpperCase());
4501 }
4502 return requestAudioFocus(l, requestAttributes, durationHint,
4503 flags & AUDIOFOCUS_FLAGS_APPS,
4504 null /* no AudioPolicy*/);
4505 }
4506
4507 /**
4508 * @hide
4509 * Request or lock audio focus.
4510 * This method is to be used by system components that have registered an
4511 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4512 * so focus granting is temporarily disabled.
4513 * @param l see the description of the same parameter in
4514 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4515 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4516 * requesting audio focus.
4517 * @param durationHint see the description of the same parameter in
4518 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4519 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004520 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004521 * <br>Use 0 when not using any flags for the request, which behaves like
4522 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4523 * focus is granted immediately, or the grant request fails because the system is in a
4524 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004525 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4526 * focus, or null.
4527 * @return see the description of the same return value in
4528 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4529 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004530 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004531 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004532 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004533 @RequiresPermission(anyOf= {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004534 Manifest.permission.MODIFY_PHONE_STATE,
4535 Manifest.permission.MODIFY_AUDIO_ROUTING
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004536 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004537 public int requestAudioFocus(OnAudioFocusChangeListener l,
4538 @NonNull AudioAttributes requestAttributes,
4539 int durationHint,
4540 int flags,
4541 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004542 // parameter checking
4543 if (requestAttributes == null) {
4544 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4545 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004546 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004547 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004548 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004549 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004550 throw new IllegalArgumentException("Illegal flags 0x"
4551 + Integer.toHexString(flags).toUpperCase());
4552 }
4553 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4554 throw new IllegalArgumentException(
4555 "Illegal null focus listener when flagged as accepting delayed focus grant");
4556 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004557 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4558 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4559 throw new IllegalArgumentException(
4560 "Illegal null focus listener when flagged as pausing instead of ducking");
4561 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004562 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4563 throw new IllegalArgumentException(
4564 "Illegal null audio policy when locking audio focus");
4565 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004566
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004567 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004568 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004569 .setAudioAttributes(requestAttributes)
4570 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4571 == AUDIOFOCUS_FLAG_DELAY_OK)
4572 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4573 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4574 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4575 .build();
4576 return requestAudioFocus(afr, ap);
4577 }
4578
4579 /**
4580 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004581 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4582 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4583 * @param afr the parameters of the request
4584 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4585 * @param clientFakeUid the UID of the client, here an arbitrary int,
4586 * doesn't have to be a real UID
4587 * @param clientTargetSdk the target SDK used by the client
4588 * @return return code indicating status of the request
4589 */
4590 @TestApi
4591 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4592 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4593 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4594 Objects.requireNonNull(afr);
4595 Objects.requireNonNull(clientFakeId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004596 int status;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004597 try {
Oscar Azucena3209c342022-05-13 19:08:14 -07004598 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004599 afr.getFocusGain(),
4600 mICallBack,
4601 mAudioFocusDispatcher,
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004602 clientFakeId, "com.android.test.fakeclient",
4603 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4604 clientFakeUid, clientTargetSdk);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004605 } catch (RemoteException e) {
4606 throw e.rethrowFromSystemServer();
4607 }
Weilin Xu1017d432022-06-08 00:27:52 +00004608 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4609 // default path with no external focus policy
4610 return status;
4611 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004612
Weilin Xu1017d432022-06-08 00:27:52 +00004613 BlockingFocusResultReceiver focusReceiver;
4614 synchronized (mFocusRequestsLock) {
4615 focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
4616 }
4617
4618 return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004619 }
4620
4621 /**
4622 * @hide
4623 * Test API to abandon audio focus for an arbitrary client.
4624 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4625 * @param afr the parameters used for the request
4626 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4627 * would be requesting
4628 * @return return code indicating status of the request
4629 */
4630 @TestApi
4631 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4632 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4633 @NonNull String clientFakeId) {
4634 Objects.requireNonNull(afr);
4635 Objects.requireNonNull(clientFakeId);
4636 try {
4637 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4638 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4639 } catch (RemoteException e) {
4640 throw e.rethrowFromSystemServer();
4641 }
4642 }
4643
4644 /**
4645 * @hide
4646 * Return the duration of the fade out applied when a player of the given AudioAttributes
4647 * is losing audio focus
4648 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4649 * @return a duration in ms, 0 indicates no fade out is applied
4650 */
4651 @TestApi
4652 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4653 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4654 {
4655 Objects.requireNonNull(aa);
4656 try {
4657 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4658 } catch (RemoteException e) {
4659 throw e.rethrowFromSystemServer();
4660 }
4661 }
4662
4663 /**
4664 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004665 * Request or lock audio focus.
4666 * This method is to be used by system components that have registered an
4667 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4668 * so focus granting is temporarily disabled.
4669 * @param afr see the description of the same parameter in
4670 * {@link #requestAudioFocus(AudioFocusRequest)}
4671 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4672 * focus, or null.
4673 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4674 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4675 * @throws NullPointerException if the AudioFocusRequest is null
4676 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4677 */
4678 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004679 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004680 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4681 if (afr == null) {
4682 throw new NullPointerException("Illegal null AudioFocusRequest");
4683 }
4684 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4685 if (afr.locksFocus() && ap == null) {
4686 throw new IllegalArgumentException(
4687 "Illegal null audio policy when locking audio focus");
4688 }
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004689
4690 if (hasCustomPolicyVirtualDeviceContext()) {
4691 // If the focus request was made within context associated with VirtualDevice
4692 // configured with custom device policy for audio, bypass audio service focus handling.
4693 // The custom device policy for audio means that audio associated with this device
4694 // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice
4695 // shouldn't affect non-virtual audio tracks (and vice versa).
4696 return AUDIOFOCUS_REQUEST_GRANTED;
4697 }
4698
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004699 registerAudioFocusRequest(afr);
4700 final IAudioService service = getService();
4701 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004702 int sdk;
4703 try {
4704 sdk = getContext().getApplicationInfo().targetSdkVersion;
4705 } catch (NullPointerException e) {
4706 // some tests don't have a Context
4707 sdk = Build.VERSION.SDK_INT;
4708 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004709
4710 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
Weilin Xu1017d432022-06-08 00:27:52 +00004711 BlockingFocusResultReceiver focusReceiver;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004712 synchronized (mFocusRequestsLock) {
Weilin Xu1017d432022-06-08 00:27:52 +00004713
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004714 try {
4715 // TODO status contains result and generation counter for ext policy
4716 status = service.requestAudioFocus(afr.getAudioAttributes(),
4717 afr.getFocusGain(), mICallBack,
4718 mAudioFocusDispatcher,
4719 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004720 getContext().getOpPackageName() /* package name */,
4721 getContext().getAttributionTag(),
4722 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004723 ap != null ? ap.cb() : null,
4724 sdk);
4725 } catch (RemoteException e) {
4726 throw e.rethrowFromSystemServer();
4727 }
Weilin Xu1017d432022-06-08 00:27:52 +00004728 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4729 // default path with no external focus policy
4730 return status;
4731 }
4732 focusReceiver = addClientIdToFocusReceiverLocked(clientId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004733 }
4734
Weilin Xu1017d432022-06-08 00:27:52 +00004735 return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver);
4736 }
4737
4738 @GuardedBy("mFocusRequestsLock")
4739 private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) {
4740 BlockingFocusResultReceiver focusReceiver;
4741 if (mFocusRequestsAwaitingResult == null) {
4742 mFocusRequestsAwaitingResult =
4743 new HashMap<String, BlockingFocusResultReceiver>(1);
4744 }
4745 focusReceiver = new BlockingFocusResultReceiver(clientId);
4746 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
4747 return focusReceiver;
Oscar Azucena3209c342022-05-13 19:08:14 -07004748 }
4749
4750 private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
Weilin Xu1017d432022-06-08 00:27:52 +00004751 BlockingFocusResultReceiver focusReceiver) {
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004752 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4753 if (DEBUG && !focusReceiver.receivedResult()) {
Oscar Azucena3209c342022-05-13 19:08:14 -07004754 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
4755 + " response from ext policy timed out, denying request");
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004756 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004757
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004758 synchronized (mFocusRequestsLock) {
4759 mFocusRequestsAwaitingResult.remove(clientId);
4760 }
4761 return focusReceiver.requestResult();
4762 }
4763
4764 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4765 private static final class SafeWaitObject {
4766 private boolean mQuit = false;
4767
4768 public void safeNotify() {
4769 synchronized (this) {
4770 mQuit = true;
4771 this.notify();
4772 }
4773 }
4774
4775 public void safeWait(long millis) throws InterruptedException {
4776 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4777 synchronized (this) {
4778 while (!mQuit) {
4779 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4780 if (timeToWait < 0) { break; }
4781 this.wait(timeToWait);
4782 }
4783 }
4784 }
4785 }
4786
4787 private static final class BlockingFocusResultReceiver {
4788 private final SafeWaitObject mLock = new SafeWaitObject();
4789 @GuardedBy("mLock")
4790 private boolean mResultReceived = false;
4791 // request denied by default (e.g. timeout)
4792 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4793 private final String mFocusClientId;
4794
4795 BlockingFocusResultReceiver(String clientId) {
4796 mFocusClientId = clientId;
4797 }
4798
4799 boolean receivedResult() { return mResultReceived; }
4800 int requestResult() { return mFocusRequestResult; }
4801
4802 void notifyResult(int requestResult) {
4803 synchronized (mLock) {
4804 mResultReceived = true;
4805 mFocusRequestResult = requestResult;
4806 mLock.safeNotify();
4807 }
4808 }
4809
4810 public void waitForResult(long timeOutMs) {
4811 synchronized (mLock) {
4812 if (mResultReceived) {
4813 // the result was received before waiting
4814 return;
4815 }
4816 try {
4817 mLock.safeWait(timeOutMs);
4818 } catch (InterruptedException e) { }
4819 }
4820 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004821 }
4822
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004823 /**
4824 * @hide
4825 * Used internally by telephony package to request audio focus. Will cause the focus request
4826 * to be associated with the "voice communication" identifier only used in AudioService
4827 * to identify this use case.
4828 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4829 * the establishment of the call
4830 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4831 * media applications resume after a call
4832 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004833 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004834 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004835 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004836 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004837 service.requestAudioFocus(new AudioAttributes.Builder()
4838 .setInternalLegacyStreamType(streamType).build(),
4839 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004840 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004841 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004842 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004843 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004844 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004845 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004846 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004847 }
4848 }
4849
4850 /**
4851 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004852 * Return the volume ramping time for a sound to be played after the given focus request,
4853 * and to play a sound of the given attributes
4854 * @param focusGain
4855 * @param attr
4856 * @return
4857 */
4858 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004859 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004860 try {
4861 return service.getFocusRampTimeMs(focusGain, attr);
4862 } catch (RemoteException e) {
4863 throw e.rethrowFromSystemServer();
4864 }
4865 }
4866
4867 /**
4868 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004869 * Set the result to the audio focus request received through
4870 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4871 * @param afi the information about the focus requester
4872 * @param requestResult the result to the focus request to be passed to the requester
4873 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4874 */
4875 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004876 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004877 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4878 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4879 if (afi == null) {
4880 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4881 }
4882 if (ap == null) {
4883 throw new IllegalArgumentException("Illegal null AudioPolicy");
4884 }
4885 final IAudioService service = getService();
4886 try {
4887 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4888 } catch (RemoteException e) {
4889 throw e.rethrowFromSystemServer();
4890 }
4891 }
4892
4893 /**
4894 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004895 * Notifies an application with a focus listener of gain or loss of audio focus.
4896 * This method can only be used by owners of an {@link AudioPolicy} configured with
4897 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4898 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4899 * that was received by the {@code AudioPolicy} through
4900 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4901 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4902 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4903 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4904 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4905 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4906 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4907 * <br>For the focus gain, the change type should be the same as the app requested.
4908 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4909 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4910 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4911 * if there was an error sending the request.
4912 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4913 */
4914 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004915 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004916 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4917 @NonNull AudioPolicy ap) {
4918 if (afi == null) {
4919 throw new NullPointerException("Illegal null AudioFocusInfo");
4920 }
4921 if (ap == null) {
4922 throw new NullPointerException("Illegal null AudioPolicy");
4923 }
4924 final IAudioService service = getService();
4925 try {
4926 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4927 } catch (RemoteException e) {
4928 throw e.rethrowFromSystemServer();
4929 }
4930 }
4931
4932 /**
4933 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004934 * Used internally by telephony package to abandon audio focus, typically after a call or
4935 * when ringing ends and the call is rejected or not answered.
4936 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4937 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004938 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004939 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004940 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004941 try {
John Spurlock61560172015-02-06 19:46:04 -05004942 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004943 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004944 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004945 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004946 }
4947 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004948
4949 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004950 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4951 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004952 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004953 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004954 */
4955 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004956 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4957 }
4958
4959 /**
4960 * @hide
4961 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4962 * @param l the listener with which focus was requested.
4963 * @param aa the {@link AudioAttributes} with which audio focus was requested
4964 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004965 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004966 */
4967 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004968 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4969 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004970 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004971 if (hasCustomPolicyVirtualDeviceContext()) {
4972 // If this AudioManager instance is running within VirtualDevice context configured
4973 // with custom device policy for audio, the audio focus handling is bypassed.
4974 return AUDIOFOCUS_REQUEST_GRANTED;
4975 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004976 unregisterAudioFocusRequest(l);
4977 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004978 try {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004979 return service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004980 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004981 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004982 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004983 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004984 }
4985
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004986 //====================================================================
4987 // Remote Control
4988 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004989 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004990 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4991 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004992 * in the application manifest. The package of the component must match that of
4993 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004994 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004995 */
RoboErikb214efb2014-07-24 13:20:30 -07004996 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004997 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004998 if (eventReceiver == null) {
4999 return;
5000 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005001 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005002 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
5003 "receiver and context package names don't match");
5004 return;
5005 }
5006 // construct a PendingIntent for the media button and register it
5007 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5008 // the associated intent will be handled by the component being registered
5009 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07005010 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07005011 0/*requestCode, ignored*/, mediaButtonIntent,
5012 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005013 registerMediaButtonIntent(pi, eventReceiver);
5014 }
5015
5016 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07005017 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
5018 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
5019 * the buttons to go to any PendingIntent. Note that you should only use this form if
5020 * you know you will continue running for the full time until unregistering the
5021 * PendingIntent.
5022 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07005023 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
5024 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
5025 * media button that was pressed.
5026 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07005027 */
RoboErikb214efb2014-07-24 13:20:30 -07005028 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07005029 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
5030 if (eventReceiver == null) {
5031 return;
5032 }
5033 registerMediaButtonIntent(eventReceiver, null);
5034 }
5035
5036 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005037 * @hide
5038 * no-op if (pi == null) or (eventReceiver == null)
5039 */
5040 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07005041 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005042 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
5043 return;
5044 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005045 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
5046 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07005047 }
5048
5049 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07005050 * Unregister the receiver of MEDIA_BUTTON intents.
5051 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5052 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07005053 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005054 */
RoboErikb214efb2014-07-24 13:20:30 -07005055 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005056 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005057 if (eventReceiver == null) {
5058 return;
5059 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005060 // construct a PendingIntent for the media button and unregister it
5061 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5062 // the associated intent will be handled by the component being registered
5063 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07005064 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07005065 0/*requestCode, ignored*/, mediaButtonIntent,
5066 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005067 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005068 }
5069
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005070 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07005071 * Unregister the receiver of MEDIA_BUTTON intents.
5072 * @param eventReceiver same PendingIntent that was registed with
5073 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07005074 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07005075 */
RoboErikb214efb2014-07-24 13:20:30 -07005076 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07005077 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
5078 if (eventReceiver == null) {
5079 return;
5080 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005081 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07005082 }
5083
5084 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005085 * @hide
5086 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005087 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07005088 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07005089 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005090 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07005091
5092 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07005093 * Registers the remote control client for providing information to display on the remote
5094 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07005095 * @param rcClient The remote control client from which remote controls will receive
5096 * information to display.
5097 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07005098 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005099 */
RoboErikb214efb2014-07-24 13:20:30 -07005100 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005101 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005102 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005103 return;
5104 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005105 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005106 }
5107
5108 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07005109 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07005110 * remote controls.
5111 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005112 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07005113 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005114 */
RoboErikb214efb2014-07-24 13:20:30 -07005115 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005116 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005117 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005118 return;
5119 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005120 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005121 }
5122
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07005123 /**
RoboErika66c40b2014-08-15 15:21:41 -07005124 * Registers a {@link RemoteController} instance for it to receive media
5125 * metadata updates and playback state information from applications using
5126 * {@link RemoteControlClient}, and control their playback.
5127 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05005128 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07005129 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005130 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07005131 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07005132 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07005133 * @return true if the {@link RemoteController} was successfully registered,
5134 * false if an error occurred, due to an internal system error, or
5135 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07005136 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07005137 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
5138 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005139 */
RoboErikb214efb2014-07-24 13:20:30 -07005140 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005141 public boolean registerRemoteController(RemoteController rctlr) {
5142 if (rctlr == null) {
5143 return false;
5144 }
RoboErik430fc482014-06-12 15:49:20 -07005145 rctlr.startListeningToSessions();
5146 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005147 }
5148
5149 /**
RoboErika66c40b2014-08-15 15:21:41 -07005150 * Unregisters a {@link RemoteController}, causing it to no longer receive
5151 * media metadata and playback state information, and no longer be capable
5152 * of controlling playback.
5153 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07005154 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07005155 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07005156 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
5157 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005158 */
RoboErikb214efb2014-07-24 13:20:30 -07005159 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005160 public void unregisterRemoteController(RemoteController rctlr) {
5161 if (rctlr == null) {
5162 return;
5163 }
RoboErik430fc482014-06-12 15:49:20 -07005164 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005165 }
5166
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005167
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005168 //====================================================================
5169 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005170 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005171 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005172 * Register the given {@link AudioPolicy}.
5173 * This call is synchronous and blocks until the registration process successfully completed
5174 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005175 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005176 * @return {@link #ERROR} if there was an error communicating with the registration service
5177 * or if the user doesn't have the required
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005178 * {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005179 * {@link #SUCCESS} otherwise.
5180 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005181 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005182 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005183 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005184 return registerAudioPolicyStatic(policy);
5185 }
5186
5187 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005188 if (policy == null) {
5189 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5190 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005191 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005192 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005193 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005194 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07005195 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
5196 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005197 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005198 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005199 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005200 } else {
5201 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005202 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005203 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005204 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005205 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005206 }
5207 return SUCCESS;
5208 }
5209
5210 /**
5211 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005212 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005213 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005214 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005215 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005216 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005217 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005218 unregisterAudioPolicyAsyncStatic(policy);
5219 }
5220
5221 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005222 if (policy == null) {
5223 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5224 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005225 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005226 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005227 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005228 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005229 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005230 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005231 }
5232 }
5233
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005234 /**
5235 * @hide
5236 * Unregisters an {@link AudioPolicy} synchronously.
5237 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
5238 * associated with mixes of this policy.
5239 * @param policy the non-null {@link AudioPolicy} to unregister.
5240 */
5241 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005242 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005243 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
5244 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
5245 final IAudioService service = getService();
5246 try {
5247 policy.invalidateCaptorsAndInjectors();
5248 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005249 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005250 } catch (RemoteException e) {
5251 throw e.rethrowFromSystemServer();
5252 }
5253 }
5254
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07005255 /**
5256 * @hide
5257 * @return true if an AudioPolicy was previously registered
5258 */
5259 @TestApi
5260 public boolean hasRegisteredDynamicPolicy() {
5261 final IAudioService service = getService();
5262 try {
5263 return service.hasRegisteredDynamicPolicy();
5264 } catch (RemoteException e) {
5265 throw e.rethrowFromSystemServer();
5266 }
5267 }
5268
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005269 //====================================================================
5270 // Notification of playback activity & playback configuration
5271 /**
5272 * Interface for receiving update notifications about the playback activity on the system.
5273 * Extend this abstract class and register it with
5274 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
5275 * to be notified.
5276 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
5277 * configuration.
5278 * @see AudioPlaybackConfiguration
5279 */
5280 public static abstract class AudioPlaybackCallback {
5281 /**
5282 * Called whenever the playback activity and configuration has changed.
5283 * @param configs list containing the results of
5284 * {@link AudioManager#getActivePlaybackConfigurations()}.
5285 */
5286 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
5287 }
5288
5289 private static class AudioPlaybackCallbackInfo {
5290 final AudioPlaybackCallback mCb;
5291 final Handler mHandler;
5292 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
5293 mCb = cb;
5294 mHandler = handler;
5295 }
5296 }
5297
5298 private final static class PlaybackConfigChangeCallbackData {
5299 final AudioPlaybackCallback mCb;
5300 final List<AudioPlaybackConfiguration> mConfigs;
5301
5302 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
5303 List<AudioPlaybackConfiguration> configs) {
5304 mCb = cb;
5305 mConfigs = configs;
5306 }
5307 }
5308
5309 /**
5310 * Register a callback to be notified of audio playback changes through
5311 * {@link AudioPlaybackCallback}
5312 * @param cb non-null callback to register
5313 * @param handler the {@link Handler} object for the thread on which to execute
5314 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5315 * {@link Looper} will be used.
5316 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005317 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
5318 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005319 {
5320 if (cb == null) {
5321 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5322 }
5323
5324 synchronized(mPlaybackCallbackLock) {
5325 // lazy initialization of the list of playback callbacks
5326 if (mPlaybackCallbackList == null) {
5327 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
5328 }
5329 final int oldCbCount = mPlaybackCallbackList.size();
5330 if (!hasPlaybackCallback_sync(cb)) {
5331 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
5332 new ServiceEventHandlerDelegate(handler).getHandler()));
5333 final int newCbCount = mPlaybackCallbackList.size();
5334 if ((oldCbCount == 0) && (newCbCount > 0)) {
5335 // register binder for callbacks
5336 try {
5337 getService().registerPlaybackCallback(mPlayCb);
5338 } catch (RemoteException e) {
5339 throw e.rethrowFromSystemServer();
5340 }
5341 }
5342 } else {
5343 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
5344 + "registered callback");
5345 }
5346 }
5347 }
5348
5349 /**
5350 * Unregister an audio playback callback previously registered with
5351 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5352 * @param cb non-null callback to unregister
5353 */
5354 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
5355 if (cb == null) {
5356 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5357 }
5358 synchronized(mPlaybackCallbackLock) {
5359 if (mPlaybackCallbackList == null) {
5360 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5361 + " that was never registered");
5362 return;
5363 }
5364 final int oldCbCount = mPlaybackCallbackList.size();
5365 if (removePlaybackCallback_sync(cb)) {
5366 final int newCbCount = mPlaybackCallbackList.size();
5367 if ((oldCbCount > 0) && (newCbCount == 0)) {
5368 // unregister binder for callbacks
5369 try {
5370 getService().unregisterPlaybackCallback(mPlayCb);
5371 } catch (RemoteException e) {
5372 throw e.rethrowFromSystemServer();
5373 }
5374 }
5375 } else {
5376 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5377 + " already unregistered or never registered");
5378 }
5379 }
5380 }
5381
5382 /**
5383 * Returns the current active audio playback configurations of the device
5384 * @return a non-null list of playback configurations. An empty list indicates there is no
5385 * playback active when queried.
5386 * @see AudioPlaybackConfiguration
5387 */
5388 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5389 final IAudioService service = getService();
5390 try {
5391 return service.getActivePlaybackConfigurations();
5392 } catch (RemoteException e) {
5393 throw e.rethrowFromSystemServer();
5394 }
5395 }
5396
5397 /**
5398 * All operations on this list are sync'd on mPlaybackCallbackLock.
5399 * List is lazy-initialized in
5400 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5401 * List can be null.
5402 */
5403 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5404 private final Object mPlaybackCallbackLock = new Object();
5405
5406 /**
5407 * Must be called synchronized on mPlaybackCallbackLock
5408 */
5409 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5410 if (mPlaybackCallbackList != null) {
5411 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5412 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5413 return true;
5414 }
5415 }
5416 }
5417 return false;
5418 }
5419
5420 /**
5421 * Must be called synchronized on mPlaybackCallbackLock
5422 */
5423 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5424 if (mPlaybackCallbackList != null) {
5425 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5426 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5427 mPlaybackCallbackList.remove(i);
5428 return true;
5429 }
5430 }
5431 }
5432 return false;
5433 }
5434
5435 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005436 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005437 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5438 boolean flush) {
5439 if (flush) {
5440 Binder.flushPendingCommands();
5441 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005442 synchronized(mPlaybackCallbackLock) {
5443 if (mPlaybackCallbackList != null) {
5444 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5445 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5446 if (arci.mHandler != null) {
5447 final Message m = arci.mHandler.obtainMessage(
5448 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5449 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5450 arci.mHandler.sendMessage(m);
5451 }
5452 }
5453 }
5454 }
5455 }
5456
5457 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005458
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005459 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005460 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005461 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005462 * Interface for receiving update notifications about the recording configuration. Extend
5463 * this abstract class and register it with
5464 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5465 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005466 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5467 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005468 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005469 */
5470 public static abstract class AudioRecordingCallback {
5471 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005472 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005473 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005474 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005475 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005476 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005477 }
5478
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005479 private static class AudioRecordingCallbackInfo {
5480 final AudioRecordingCallback mCb;
5481 final Handler mHandler;
5482 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5483 mCb = cb;
5484 mHandler = handler;
5485 }
5486 }
5487
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005488 private final static class RecordConfigChangeCallbackData {
5489 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005490 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005491
5492 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005493 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005494 mCb = cb;
5495 mConfigs = configs;
5496 }
5497 }
5498
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005499 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005500 * Register a callback to be notified of audio recording changes through
5501 * {@link AudioRecordingCallback}
5502 * @param cb non-null callback to register
5503 * @param handler the {@link Handler} object for the thread on which to execute
5504 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5505 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005506 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005507 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5508 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005509 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005510 if (cb == null) {
5511 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5512 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005513
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005514 synchronized(mRecordCallbackLock) {
5515 // lazy initialization of the list of recording callbacks
5516 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005517 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005518 }
5519 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005520 if (!hasRecordCallback_sync(cb)) {
5521 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5522 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005523 final int newCbCount = mRecordCallbackList.size();
5524 if ((oldCbCount == 0) && (newCbCount > 0)) {
5525 // register binder for callbacks
5526 final IAudioService service = getService();
5527 try {
5528 service.registerRecordingCallback(mRecCb);
5529 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005530 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005531 }
5532 }
5533 } else {
5534 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5535 + "registered callback");
5536 }
5537 }
5538 }
5539
5540 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005541 * Unregister an audio recording callback previously registered with
5542 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5543 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005544 */
5545 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5546 if (cb == null) {
5547 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5548 }
5549 synchronized(mRecordCallbackLock) {
5550 if (mRecordCallbackList == null) {
5551 return;
5552 }
5553 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005554 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005555 final int newCbCount = mRecordCallbackList.size();
5556 if ((oldCbCount > 0) && (newCbCount == 0)) {
5557 // unregister binder for callbacks
5558 final IAudioService service = getService();
5559 try {
5560 service.unregisterRecordingCallback(mRecCb);
5561 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005562 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005563 }
5564 }
5565 } else {
5566 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5567 + " already unregistered or never registered");
5568 }
5569 }
5570 }
5571
5572 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005573 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005574 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005575 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005576 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005577 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005578 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005579 final IAudioService service = getService();
5580 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005581 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005582 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005583 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005584 }
5585 }
5586
5587 /**
5588 * constants for the recording events, to keep in sync
5589 * with frameworks/av/include/media/AudioPolicy.h
5590 */
5591 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005592 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005593 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005594 public static final int RECORD_CONFIG_EVENT_START = 0;
5595 /** @hide */
5596 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5597 /** @hide */
5598 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5599 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005600 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005601 /**
5602 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5603 */
5604 /** @hide */
5605 public static final int RECORD_RIID_INVALID = -1;
5606 /** @hide */
5607 public static final int RECORDER_STATE_STARTED = 0;
5608 /** @hide */
5609 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005610
5611 /**
5612 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005613 * List is lazy-initialized in
5614 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005615 * List can be null.
5616 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005617 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005618 private final Object mRecordCallbackLock = new Object();
5619
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005620 /**
5621 * Must be called synchronized on mRecordCallbackLock
5622 */
5623 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5624 if (mRecordCallbackList != null) {
5625 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5626 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5627 return true;
5628 }
5629 }
5630 }
5631 return false;
5632 }
5633
5634 /**
5635 * Must be called synchronized on mRecordCallbackLock
5636 */
5637 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5638 if (mRecordCallbackList != null) {
5639 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5640 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5641 mRecordCallbackList.remove(i);
5642 return true;
5643 }
5644 }
5645 }
5646 return false;
5647 }
5648
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005649 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005650 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005651 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005652 synchronized(mRecordCallbackLock) {
5653 if (mRecordCallbackList != null) {
5654 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5655 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5656 if (arci.mHandler != null) {
5657 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005658 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5659 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005660 arci.mHandler.sendMessage(m);
5661 }
5662 }
5663 }
5664 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005665 }
5666
5667 };
5668
5669 //=====================================================================
5670
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005671 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005672 * @hide
5673 * Reload audio settings. This method is called by Settings backup
5674 * agent when audio settings are restored and causes the AudioService
5675 * to read and apply restored settings.
5676 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005677 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005678 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005679 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005680 try {
5681 service.reloadAudioSettings();
5682 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005683 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005684 }
5685 }
5686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005687 /**
5688 * {@hide}
5689 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005690 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005691
5692 /**
5693 * Checks whether the phone is in silent mode, with or without vibrate.
5694 *
5695 * @return true if phone is in silent mode, with or without vibrate.
5696 *
5697 * @see #getRingerMode()
5698 *
5699 * @hide pending API Council approval
5700 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005701 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005702 public boolean isSilentMode() {
5703 int ringerMode = getRingerMode();
5704 boolean silentMode =
5705 (ringerMode == RINGER_MODE_SILENT) ||
5706 (ringerMode == RINGER_MODE_VIBRATE);
5707 return silentMode;
5708 }
5709
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005710 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5711 // class is not used by other parts of the framework, which instead use definitions and methods
5712 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5713
Eric Laurent948d3272014-05-16 15:18:45 -07005714 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005715 * The audio device code for representing "no device." */
5716 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5717 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005718 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005719 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5720 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5721 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5722 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005723 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005724 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005725 /** @hide
5726 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005727 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005728 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005729 /** @hide
5730 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005731 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005732 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005733 /** @hide
5734 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005735 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005736 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005737 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005738 * The audio output device code for a USB headphone with attached microphone */
5739 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5740 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005741 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005742 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005743 /** @hide
5744 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5745 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005746 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005747 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005748 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5749 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005750 /** @hide
5751 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005752 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5753 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005754 /** @hide
5755 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005756 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005757 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005758 /** @hide
5759 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005760 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005761 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5762 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005763 /** @hide
5764 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005765 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005766 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5767 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005768 /** @hide
5769 * The audio output device code for S/PDIF (legacy) or HDMI
5770 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005771 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005772 /** @hide
5773 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005774 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005775 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5776 /** @hide
5777 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005778 * docking station
5779 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005780 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005781 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005782 /** @hide
5783 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005784 * docking station
5785 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005786 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005787 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005788 /** @hide
5789 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005790 * mode and the Android device in USB device mode
5791 */
5792 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005793 /** @hide
5794 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005795 * mode and the Android device in USB host mode
5796 */
5797 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005798 /** @hide
5799 * The audio output device code for projection output.
5800 */
5801 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5802 /** @hide
5803 * The audio output device code the telephony voice TX path.
5804 */
5805 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5806 /** @hide
5807 * The audio output device code for an analog jack with line impedance detected.
5808 */
5809 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5810 /** @hide
5811 * The audio output device code for HDMI Audio Return Channel.
5812 */
5813 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5814 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005815 * The audio output device code for HDMI enhanced Audio Return Channel.
5816 */
5817 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5818 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005819 * The audio output device code for S/PDIF digital connection.
5820 */
5821 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5822 /** @hide
5823 * The audio output device code for built-in FM transmitter.
5824 */
5825 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5826 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005827 * The audio output device code for echo reference injection point.
5828 */
5829 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5830 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005831 * The audio output device code for a BLE audio headset.
5832 */
5833 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5834 /** @hide
5835 * The audio output device code for a BLE audio speaker.
5836 */
5837 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5838 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01005839 * The audio output device code for a BLE audio brodcast group.
5840 */
5841 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
5842 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005843 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005844 * used in the future in a set method to select whatever default device is chosen by the
5845 * platform-specific implementation.
5846 */
5847 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5848
Eric Laurent948d3272014-05-16 15:18:45 -07005849 /** @hide
5850 * The audio input device code for default built-in microphone
5851 */
5852 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5853 /** @hide
5854 * The audio input device code for a Bluetooth SCO headset
5855 */
5856 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5857 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5858 /** @hide
5859 * The audio input device code for wired headset microphone
5860 */
5861 public static final int DEVICE_IN_WIRED_HEADSET =
5862 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5863 /** @hide
5864 * The audio input device code for HDMI
5865 */
5866 public static final int DEVICE_IN_HDMI =
5867 AudioSystem.DEVICE_IN_HDMI;
5868 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005869 * The audio input device code for HDMI ARC
5870 */
5871 public static final int DEVICE_IN_HDMI_ARC =
5872 AudioSystem.DEVICE_IN_HDMI_ARC;
5873
5874 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005875 * The audio input device code for HDMI EARC
5876 */
5877 public static final int DEVICE_IN_HDMI_EARC =
5878 AudioSystem.DEVICE_IN_HDMI_EARC;
5879
5880 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005881 * The audio input device code for telephony voice RX path
5882 */
5883 public static final int DEVICE_IN_TELEPHONY_RX =
5884 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5885 /** @hide
5886 * The audio input device code for built-in microphone pointing to the back
5887 */
5888 public static final int DEVICE_IN_BACK_MIC =
5889 AudioSystem.DEVICE_IN_BACK_MIC;
5890 /** @hide
5891 * The audio input device code for analog from a docking station
5892 */
5893 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5894 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5895 /** @hide
5896 * The audio input device code for digital from a docking station
5897 */
5898 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5899 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5900 /** @hide
5901 * The audio input device code for a USB audio accessory. The accessory is in USB host
5902 * mode and the Android device in USB device mode
5903 */
5904 public static final int DEVICE_IN_USB_ACCESSORY =
5905 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5906 /** @hide
5907 * The audio input device code for a USB audio device. The device is in USB device
5908 * mode and the Android device in USB host mode
5909 */
5910 public static final int DEVICE_IN_USB_DEVICE =
5911 AudioSystem.DEVICE_IN_USB_DEVICE;
5912 /** @hide
5913 * The audio input device code for a FM radio tuner
5914 */
5915 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5916 /** @hide
5917 * The audio input device code for a TV tuner
5918 */
5919 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5920 /** @hide
5921 * The audio input device code for an analog jack with line impedance detected
5922 */
5923 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5924 /** @hide
5925 * The audio input device code for a S/PDIF digital connection
5926 */
5927 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005928 /** @hide
5929 * The audio input device code for audio loopback
5930 */
5931 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005932 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005933 * The audio input device code for an echo reference capture point.
5934 */
5935 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5936 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005937 * The audio input device code for a BLE audio headset.
5938 */
5939 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005940
5941 /**
5942 * Return true if the device code corresponds to an output device.
5943 * @hide
5944 */
5945 public static boolean isOutputDevice(int device)
5946 {
5947 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5948 }
5949
5950 /**
5951 * Return true if the device code corresponds to an input device.
5952 * @hide
5953 */
5954 public static boolean isInputDevice(int device)
5955 {
5956 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5957 }
5958
5959
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005960 /**
5961 * Return the enabled devices for the specified output stream type.
5962 *
5963 * @param streamType The stream type to query. One of
5964 * {@link #STREAM_VOICE_CALL},
5965 * {@link #STREAM_SYSTEM},
5966 * {@link #STREAM_RING},
5967 * {@link #STREAM_MUSIC},
5968 * {@link #STREAM_ALARM},
5969 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005970 * {@link #STREAM_DTMF},
5971 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005972 *
5973 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5974 * stream. Zero or more of
5975 * {@link #DEVICE_OUT_EARPIECE},
5976 * {@link #DEVICE_OUT_SPEAKER},
5977 * {@link #DEVICE_OUT_WIRED_HEADSET},
5978 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5979 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5980 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5981 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5982 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5983 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5984 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005985 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005986 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5987 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005988 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5989 * {@link #DEVICE_OUT_USB_DEVICE}.
5990 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5991 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5992 * {@link #DEVICE_OUT_LINE}.
5993 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005994 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005995 * {@link #DEVICE_OUT_SPDIF}.
5996 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005997 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5998 *
5999 * The implementation may support additional device codes beyond those listed, so
6000 * the application should ignore any bits which it does not recognize.
6001 * Note that the information may be imprecise when the implementation
6002 * cannot distinguish whether a particular device is enabled.
6003 *
Andy Hungb11e4c72021-04-13 19:31:00 -07006004 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
6005 * will have multi-bit device types.
6006 * Prefer to use {@link #getDevicesForAttributes()} instead,
6007 * noting that getDevicesForStream() has a few small discrepancies
6008 * for better volume handling.
6009 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006010 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006011 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07006012 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006013 public int getDevicesForStream(int streamType) {
6014 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07006015 case STREAM_VOICE_CALL:
6016 case STREAM_SYSTEM:
6017 case STREAM_RING:
6018 case STREAM_MUSIC:
6019 case STREAM_ALARM:
6020 case STREAM_NOTIFICATION:
6021 case STREAM_DTMF:
6022 case STREAM_ACCESSIBILITY:
6023 final IAudioService service = getService();
6024 try {
6025 return service.getDeviceMaskForStream(streamType);
6026 } catch (RemoteException e) {
6027 throw e.rethrowFromSystemServer();
6028 }
6029 default:
6030 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006031 }
6032 }
6033
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08006034 /**
6035 * @hide
6036 * Get the audio devices that would be used for the routing of the given audio attributes.
6037 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6038 * @return an empty list if there was an issue with the request, a list of audio devices
6039 * otherwise (typically one device, except for duplicated paths).
6040 */
6041 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006042 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006043 Manifest.permission.MODIFY_AUDIO_ROUTING,
6044 Manifest.permission.QUERY_AUDIO_STATE
kholoud mohamed37839212021-03-15 16:49:06 +00006045 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08006046 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08006047 @NonNull AudioAttributes attributes) {
6048 Objects.requireNonNull(attributes);
6049 final IAudioService service = getService();
6050 try {
6051 return service.getDevicesForAttributes(attributes);
6052 } catch (RemoteException e) {
6053 throw e.rethrowFromSystemServer();
6054 }
6055 }
6056
Paul Wangebadb692022-12-15 20:40:19 +00006057 // Each listener corresponds to a unique callback stub because each listener can subscribe to
6058 // different AudioAttributes.
6059 private final ConcurrentHashMap<OnDevicesForAttributesChangedListener,
6060 IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub =
6061 new ConcurrentHashMap<>();
6062
6063 private static final class IDevicesForAttributesCallbackStub
6064 extends IDevicesForAttributesCallback.Stub {
6065 ListenerInfo<OnDevicesForAttributesChangedListener> mInfo;
6066
6067 IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener,
6068 @NonNull Executor executor) {
6069 mInfo = new ListenerInfo<>(listener, executor);
6070 }
6071
6072 public void register(boolean register, AudioAttributes attributes) {
6073 try {
6074 if (register) {
6075 getService().addOnDevicesForAttributesChangedListener(attributes, this);
6076 } else {
6077 getService().removeOnDevicesForAttributesChangedListener(this);
6078 }
6079 } catch (RemoteException e) {
6080 throw e.rethrowFromSystemServer();
6081 }
6082 }
6083
6084 @Override
6085 public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume,
6086 List<AudioDeviceAttributes> devices) {
6087 // forVolume is ignored. The case where it is `true` is not handled.
6088 mInfo.mExecutor.execute(() ->
6089 mInfo.mListener.onDevicesForAttributesChanged(
6090 attributes, devices));
6091 }
6092 }
6093
6094 /**
6095 * @hide
6096 * Interface to be notified of when routing changes for the registered audio attributes.
6097 */
6098 @SystemApi
6099 public interface OnDevicesForAttributesChangedListener {
6100 /**
6101 * Called on the listener to indicate that the audio devices for the given audio
6102 * attributes have changed.
6103 * @param attributes the {@link AudioAttributes} whose routing changed
6104 * @param devices a list of newly routed audio devices
6105 */
6106 void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
6107 @NonNull List<AudioDeviceAttributes> devices);
6108 }
6109
6110 /**
6111 * @hide
6112 * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}.
6113 * @param attributes the {@link AudioAttributes} to listen for routing changes
6114 * @param executor
6115 * @param listener
6116 */
6117 @SystemApi
6118 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006119 Manifest.permission.MODIFY_AUDIO_ROUTING,
6120 Manifest.permission.QUERY_AUDIO_STATE
Paul Wangebadb692022-12-15 20:40:19 +00006121 })
6122 public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
6123 @NonNull @CallbackExecutor Executor executor,
6124 @NonNull OnDevicesForAttributesChangedListener listener) {
6125 Objects.requireNonNull(attributes);
6126 Objects.requireNonNull(executor);
6127 Objects.requireNonNull(listener);
6128
6129 synchronized (mDevicesForAttributesListenerToStub) {
6130 IDevicesForAttributesCallbackStub callbackStub =
6131 mDevicesForAttributesListenerToStub.get(listener);
6132
6133 if (callbackStub == null) {
6134 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor);
6135 mDevicesForAttributesListenerToStub.put(listener, callbackStub);
6136 }
6137
6138 callbackStub.register(true, attributes);
6139 }
6140 }
6141
6142 /**
6143 * @hide
6144 * Removes a previously registered listener for being notified of routing changes for the given
6145 * {@link AudioAttributes}.
6146 * @param listener
6147 */
6148 @SystemApi
6149 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006150 Manifest.permission.MODIFY_AUDIO_ROUTING,
6151 Manifest.permission.QUERY_AUDIO_STATE
Paul Wangebadb692022-12-15 20:40:19 +00006152 })
6153 public void removeOnDevicesForAttributesChangedListener(
6154 @NonNull OnDevicesForAttributesChangedListener listener) {
6155 Objects.requireNonNull(listener);
6156
6157 synchronized (mDevicesForAttributesListenerToStub) {
6158 IDevicesForAttributesCallbackStub callbackStub =
6159 mDevicesForAttributesListenerToStub.get(listener);
6160 if (callbackStub != null) {
6161 callbackStub.register(false, null /* attributes */);
6162 }
6163
6164 mDevicesForAttributesListenerToStub.remove(listener);
6165 }
6166 }
6167
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006168 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01006169 * Get the audio devices that would be used for the routing of the given audio attributes.
6170 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
6171 * the specified {@link AudioAttributes}.
6172 * The audio routing can change if audio devices are physically connected or disconnected or
6173 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
6174 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6175 * @return an empty list if there was an issue with the request, a list of
6176 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
6177 */
6178 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
6179 @NonNull AudioAttributes attributes) {
6180 final List<AudioDeviceAttributes> devicesForAttributes;
6181 try {
6182 Objects.requireNonNull(attributes);
6183 final IAudioService service = getService();
6184 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
6185 } catch (Exception e) {
6186 Log.i(TAG, "No audio devices available for specified attributes.");
6187 return Collections.emptyList();
6188 }
6189
6190 // Map from AudioDeviceAttributes to AudioDeviceInfo
6191 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
6192 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
6193 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
6194 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
6195 if (deviceForAttributes.getType() == deviceInfo.getType()
6196 && TextUtils.equals(deviceForAttributes.getAddress(),
6197 deviceInfo.getAddress())) {
6198 deviceInfosForAttributes.add(deviceInfo);
6199 }
6200 }
6201 }
6202 return Collections.unmodifiableList(deviceInfosForAttributes);
6203 }
6204
6205 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006206 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006207 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02006208 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
6209 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006210 */
6211 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
6212 /**
6213 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006214 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02006215 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006216 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006217 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006218 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
6219 /**
6220 * @hide
6221 * Volume behavior for an audio device where the volume is always set to provide no attenuation
6222 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006223 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006224 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006225 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006226 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
6227 /**
6228 * @hide
6229 * Volume behavior for an audio device where the volume is either set to muted, or to provide
6230 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006231 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006232 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006233 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006234 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
6235 /**
6236 * @hide
6237 * Volume behavior for an audio device where no software attenuation is applied, and
6238 * the volume is kept synchronized between the host and the device itself through a
6239 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02006240 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006241 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006242 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006243 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
6244 /**
6245 * @hide
6246 * Volume behavior for an audio device where no software attenuation is applied, and
6247 * the volume is kept synchronized between the host and the device itself through a
6248 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
6249 * normal vs in phone call).
6250 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02006251 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006252 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006253 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006254 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
6255
Yan Han6f96eec2023-01-20 14:22:15 +01006256 /**
6257 * @hide
6258 * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
6259 * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have
6260 * no effect, or an unreliable effect.
6261 */
6262 @SystemApi
6263 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
6264
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006265 /** @hide */
6266 @IntDef({
6267 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6268 DEVICE_VOLUME_BEHAVIOR_FULL,
6269 DEVICE_VOLUME_BEHAVIOR_FIXED,
6270 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6271 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
Yan Han6f96eec2023-01-20 14:22:15 +01006272 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006273 })
6274 @Retention(RetentionPolicy.SOURCE)
6275 public @interface DeviceVolumeBehavior {}
6276
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006277 /** @hide */
6278 @IntDef({
6279 DEVICE_VOLUME_BEHAVIOR_UNSET,
6280 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6281 DEVICE_VOLUME_BEHAVIOR_FULL,
6282 DEVICE_VOLUME_BEHAVIOR_FIXED,
6283 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6284 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
Yan Han6f96eec2023-01-20 14:22:15 +01006285 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006286 })
6287 @Retention(RetentionPolicy.SOURCE)
6288 public @interface DeviceVolumeBehaviorState {}
6289
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006290 /**
Yan Han6f96eec2023-01-20 14:22:15 +01006291 * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}.
6292 * @hide
6293 */
6294 @IntDef({
6295 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6296 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
6297 })
6298 @Retention(RetentionPolicy.SOURCE)
6299 public @interface AbsoluteDeviceVolumeBehavior {}
6300
6301 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006302 * @hide
6303 * Throws IAE on an invalid volume behavior value
6304 * @param volumeBehavior behavior value to check
6305 */
6306 public static void enforceValidVolumeBehavior(int volumeBehavior) {
6307 switch (volumeBehavior) {
6308 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
6309 case DEVICE_VOLUME_BEHAVIOR_FULL:
6310 case DEVICE_VOLUME_BEHAVIOR_FIXED:
6311 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
6312 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
Yan Han6f96eec2023-01-20 14:22:15 +01006313 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006314 return;
6315 default:
6316 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
6317 }
6318 }
6319
6320 /**
6321 * @hide
6322 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02006323 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
6324 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
6325 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
6326 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
6327 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
6328 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006329 * @param deviceVolumeBehavior one of the device behaviors
6330 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006331 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006332 @RequiresPermission(anyOf = {
6333 Manifest.permission.MODIFY_AUDIO_ROUTING,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006334 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006335 })
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006336 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
6337 @DeviceVolumeBehavior int deviceVolumeBehavior) {
6338 // verify arguments (validity of device type is enforced in server)
6339 Objects.requireNonNull(device);
6340 enforceValidVolumeBehavior(deviceVolumeBehavior);
6341 // communicate with service
6342 final IAudioService service = getService();
6343 try {
6344 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
6345 mApplicationContext.getOpPackageName());
6346 } catch (RemoteException e) {
6347 throw e.rethrowFromSystemServer();
6348 }
6349 }
6350
6351 /**
6352 * @hide
Yan Han6f96eec2023-01-20 14:22:15 +01006353 * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by
6354 * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned
6355 * in its place.
6356 */
6357 @ChangeId
6358 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
Yan Han31b10112023-02-13 17:25:46 +01006359 @Overridable
Yan Han6f96eec2023-01-20 14:22:15 +01006360 public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L;
6361
6362 /**
6363 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006364 * Returns the volume device behavior for the given audio device
6365 * @param device the audio device
6366 * @return the volume behavior for the device
6367 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006368 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006369 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006370 Manifest.permission.MODIFY_AUDIO_ROUTING,
6371 Manifest.permission.QUERY_AUDIO_STATE,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006372 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
kholoud mohamed37839212021-03-15 16:49:06 +00006373 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02006374 public @DeviceVolumeBehavior
6375 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006376 // verify arguments (validity of device type is enforced in server)
6377 Objects.requireNonNull(device);
6378 // communicate with service
6379 final IAudioService service = getService();
6380 try {
Yan Han6f96eec2023-01-20 14:22:15 +01006381 int behavior = service.getDeviceVolumeBehavior(device);
6382 if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)
6383 && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
6384 return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
6385 }
6386 return behavior;
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006387 } catch (RemoteException e) {
6388 throw e.rethrowFromSystemServer();
6389 }
6390 }
6391
kholoud mohamed37839212021-03-15 16:49:06 +00006392 /**
6393 * @hide
6394 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
6395 */
6396 @TestApi
6397 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006398 Manifest.permission.MODIFY_AUDIO_ROUTING,
6399 Manifest.permission.QUERY_AUDIO_STATE,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006400 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
kholoud mohamed37839212021-03-15 16:49:06 +00006401 })
6402 public boolean isFullVolumeDevice() {
6403 final AudioAttributes attributes = new AudioAttributes.Builder()
6404 .setUsage(AudioAttributes.USAGE_MEDIA)
6405 .build();
6406 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
6407 for (AudioDeviceAttributes device : devices) {
6408 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
6409 return true;
6410 }
6411 }
6412 return false;
6413 }
6414
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006415 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006416 * Indicate wired accessory connection state change.
6417 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
6418 * @param state new connection state: 1 connected, 0 disconnected
6419 * @param name device name
6420 * {@hide}
6421 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006422 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006423 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair7b72c392022-04-04 13:25:46 +02006424 public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
6425 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006426 setWiredDeviceConnectionState(attributes, state);
6427 }
6428
6429 /**
6430 * Indicate wired accessory connection state change and attributes.
6431 * @param state new connection state: 1 connected, 0 disconnected
6432 * @param attributes attributes of the connected device
6433 * {@hide}
6434 */
6435 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006436 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006437 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07006438 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006439 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006440 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07006441 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006442 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006443 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006444 }
6445 }
6446
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00006447 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006448 * Indicate wired accessory connection state change.
6449 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
6450 * @param connected true for connected, false for disconnected
6451 * {@hide}
6452 */
6453 @TestApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006454 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006455 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
6456 boolean connected) {
6457 try {
6458 getService().setTestDeviceConnectionState(device, connected);
6459 } catch (RemoteException e) {
6460 throw e.rethrowFromSystemServer();
6461 }
6462 }
6463
6464 /**
wescande7c17ba0c2021-07-30 16:46:14 +02006465 * Indicate Bluetooth profile connection state change.
6466 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
6467 * <code>previousDevice</code>
6468 * This operation is asynchronous.
6469 *
6470 * @param newDevice Bluetooth device connected or null if there is no new devices
6471 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
6472 * devices
William Escandeac11d772022-01-25 18:01:15 +01006473 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006474 * {@hide}
6475 */
wescande7c17ba0c2021-07-30 16:46:14 +02006476 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006477 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
wescande7c17ba0c2021-07-30 16:46:14 +02006478 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01006479 @Nullable BluetoothDevice previousDevice,
6480 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006481 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006482 try {
wescande7c17ba0c2021-07-30 16:46:14 +02006483 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006484 } catch (RemoteException e) {
6485 throw e.rethrowFromSystemServer();
6486 }
6487 }
6488
Jeff Sharkey098d5802012-04-26 17:30:34 -07006489 /** {@hide} */
6490 public IRingtonePlayer getRingtonePlayer() {
6491 try {
6492 return getService().getRingtonePlayer();
6493 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006494 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006495 }
6496 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006497
6498 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006499 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07006500 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
6501 * should use this value as a default, and offer the user the option to override it.
6502 * The low latency output stream is typically either the device's primary output stream,
6503 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006504 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006505 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006506 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
6507 "android.media.property.OUTPUT_SAMPLE_RATE";
6508
6509 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006510 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07006511 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
6512 * should use this value as a minimum, and offer the user the option to override it.
6513 * The low latency output stream is typically either the device's primary output stream,
6514 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006515 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006516 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006517 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
6518 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
6519
6520 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07006521 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
6522 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6523 */
6524 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6525 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6526
6527 /**
6528 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6529 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6530 */
6531 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6532 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6533
6534 /**
ragoa7cc59c2015-12-02 11:31:15 -08006535 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6536 * available and supported with the expected frequency range and level response.
6537 */
6538 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6539 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6540 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006541 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006542 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006543 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6544 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006545 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6546 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6547 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006548 * @return A string representing the associated value for that property key,
6549 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006550 */
6551 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006552 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6553 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6554 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6555 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6556 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6557 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006558 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006559 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6560 // not found.
6561 return String.valueOf(getContext().getResources().getBoolean(
6562 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006563 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006564 return String.valueOf(getContext().getResources().getBoolean(
6565 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006566 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6567 return String.valueOf(getContext().getResources().getBoolean(
6568 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006569 } else {
6570 // null or unknown key
6571 return null;
6572 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006573 }
6574
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006575 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006576 * @hide
6577 * Sets an additional audio output device delay in milliseconds.
6578 *
6579 * The additional output delay is a request to the output device to
6580 * delay audio presentation (generally with respect to video presentation for better
6581 * synchronization).
6582 * It may not be supported by all output devices,
6583 * and typically increases the audio latency by the amount of additional
6584 * audio delay requested.
6585 *
6586 * If additional audio delay is supported by an audio output device,
6587 * it is expected to be supported for all output streams (and configurations)
6588 * opened on that device.
6589 *
6590 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006591 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006592 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6593 * @return true if successful, false if the device does not support output device delay
6594 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6595 */
6596 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006597 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Andy Hung97aa07f82020-01-17 14:05:06 -08006598 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006599 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006600 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006601 try {
6602 return getService().setAdditionalOutputDeviceDelay(
6603 new AudioDeviceAttributes(device), delayMillis);
6604 } catch (RemoteException e) {
6605 throw e.rethrowFromSystemServer();
6606 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006607 }
6608
6609 /**
6610 * @hide
6611 * Returns the current additional audio output device delay in milliseconds.
6612 *
6613 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6614 * @return the additional output device delay. This is a non-negative number.
6615 * {@code 0} is returned if unsupported.
6616 */
6617 @SystemApi
6618 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006619 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006620 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006621 try {
6622 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6623 } catch (RemoteException e) {
6624 throw e.rethrowFromSystemServer();
6625 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006626 }
6627
6628 /**
6629 * @hide
6630 * Returns the maximum additional audio output device delay in milliseconds.
6631 *
6632 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6633 * @return the maximum output device delay in milliseconds that can be set.
6634 * This is a non-negative number
6635 * representing the additional audio delay supported for the device.
6636 * {@code 0} is returned if unsupported.
6637 */
6638 @SystemApi
6639 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006640 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006641 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006642 try {
6643 return getService().getMaxAdditionalOutputDeviceDelay(
6644 new AudioDeviceAttributes(device));
6645 } catch (RemoteException e) {
6646 throw e.rethrowFromSystemServer();
6647 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006648 }
6649
6650 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006651 * Returns the estimated latency for the given stream type in milliseconds.
6652 *
6653 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6654 * a better solution.
6655 * @hide
6656 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006657 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006658 public int getOutputLatency(int streamType) {
6659 return AudioSystem.getOutputLatency(streamType);
6660 }
6661
John Spurlock3346a802014-05-20 16:25:37 -04006662 /**
6663 * Registers a global volume controller interface. Currently limited to SystemUI.
6664 *
6665 * @hide
6666 */
6667 public void setVolumeController(IVolumeController controller) {
6668 try {
6669 getService().setVolumeController(controller);
6670 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006671 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006672 }
6673 }
6674
6675 /**
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006676 * Returns the registered volume controller interface.
6677 *
6678 * @hide
6679 */
6680 @Nullable
6681 public IVolumeController getVolumeController() {
6682 try {
6683 return getService().getVolumeController();
6684 } catch (RemoteException e) {
6685 throw e.rethrowFromSystemServer();
6686 }
6687 }
6688
6689 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006690 * Notify audio manager about volume controller visibility changes.
6691 * Currently limited to SystemUI.
6692 *
6693 * @hide
6694 */
6695 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6696 try {
6697 getService().notifyVolumeControllerVisible(controller, visible);
6698 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006699 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006700 }
6701 }
6702
6703 /**
John Spurlock3346a802014-05-20 16:25:37 -04006704 * Only useful for volume controllers.
6705 * @hide
6706 */
John Spurlock3346a802014-05-20 16:25:37 -04006707 public boolean isStreamAffectedByRingerMode(int streamType) {
6708 try {
6709 return getService().isStreamAffectedByRingerMode(streamType);
6710 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006711 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006712 }
6713 }
6714
6715 /**
6716 * Only useful for volume controllers.
6717 * @hide
6718 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006719 public boolean isStreamAffectedByMute(int streamType) {
6720 try {
6721 return getService().isStreamAffectedByMute(streamType);
6722 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006723 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006724 }
6725 }
6726
6727 /**
6728 * Only useful for volume controllers.
6729 * @hide
6730 */
John Spurlock3346a802014-05-20 16:25:37 -04006731 public void disableSafeMediaVolume() {
6732 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006733 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006734 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006735 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006736 }
6737 }
Eric Laurenta198a292014-02-18 16:26:17 -08006738
6739 /**
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00006740 * @hide
6741 * Lower media volume to RS1
6742 */
6743 public void lowerVolumeToRs1() {
6744 try {
6745 getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName());
6746 } catch (RemoteException e) {
6747 throw e.rethrowFromSystemServer();
6748 }
6749 }
6750
6751 /**
6752 * @hide
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006753 * @return the RS2 value used for momentary exposure warnings
6754 */
6755 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006756 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006757 public float getRs2Value() {
6758 try {
6759 return getService().getRs2Value();
6760 } catch (RemoteException e) {
6761 throw e.rethrowFromSystemServer();
6762 }
6763 }
6764
6765 /**
6766 * @hide
6767 * Sets the RS2 value used for momentary exposure warnings
6768 */
6769 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006770 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006771 public void setRs2Value(float rs2Value) {
6772 try {
6773 getService().setRs2Value(rs2Value);
6774 } catch (RemoteException e) {
6775 throw e.rethrowFromSystemServer();
6776 }
6777 }
6778
6779 /**
6780 * @hide
6781 * @return the current computed sound dose value
6782 */
6783 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006784 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006785 public float getCsd() {
6786 try {
6787 return getService().getCsd();
6788 } catch (RemoteException e) {
6789 throw e.rethrowFromSystemServer();
6790 }
6791 }
6792
6793 /**
6794 * @hide
6795 * Sets the computed sound dose value to {@code csd}
6796 */
6797 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006798 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006799 public void setCsd(float csd) {
6800 try {
6801 getService().setCsd(csd);
6802 } catch (RemoteException e) {
6803 throw e.rethrowFromSystemServer();
6804 }
6805 }
6806
6807 /**
6808 * @hide
6809 * Forces the computation of MEL values (used for CSD) on framework level. This will have the
6810 * result of ignoring the MEL values computed on HAL level. Should only be used in testing
6811 * since this can affect the certification of a device with EN50332-3 regulation.
6812 */
6813 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006814 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006815 public void forceUseFrameworkMel(boolean useFrameworkMel) {
6816 try {
6817 getService().forceUseFrameworkMel(useFrameworkMel);
6818 } catch (RemoteException e) {
6819 throw e.rethrowFromSystemServer();
6820 }
6821 }
6822
6823 /**
6824 * @hide
6825 * Forces the computation of CSD on all output devices.
6826 */
6827 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006828 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006829 public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
6830 try {
6831 getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices);
6832 } catch (RemoteException e) {
6833 throw e.rethrowFromSystemServer();
6834 }
6835 }
6836
6837 /**
6838 * @hide
6839 * Returns whether CSD is enabled on this device.
6840 */
6841 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006842 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006843 public boolean isCsdEnabled() {
6844 try {
6845 return getService().isCsdEnabled();
6846 } catch (RemoteException e) {
6847 throw e.rethrowFromSystemServer();
6848 }
6849 }
6850
6851 /**
6852 * @hide
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00006853 * Sound dose warning at every 100% of dose during integration window
6854 */
6855 public static final int CSD_WARNING_DOSE_REACHED_1X = 1;
6856 /**
6857 * @hide
6858 * Sound dose warning when 500% of dose is reached during integration window
6859 */
6860 public static final int CSD_WARNING_DOSE_REPEATED_5X = 2;
6861 /**
6862 * @hide
6863 * Sound dose warning after a momentary exposure event
6864 */
6865 public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3;
6866 /**
6867 * @hide
6868 * Sound dose warning at every 100% of dose during integration window
6869 */
6870 public static final int CSD_WARNING_ACCUMULATION_START = 4;
6871
6872 /** @hide */
6873 @IntDef(flag = false, value = {
6874 CSD_WARNING_DOSE_REACHED_1X,
6875 CSD_WARNING_DOSE_REPEATED_5X,
6876 CSD_WARNING_MOMENTARY_EXPOSURE,
6877 CSD_WARNING_ACCUMULATION_START }
6878 )
6879 @Retention(RetentionPolicy.SOURCE)
6880 public @interface CsdWarning {}
6881
6882 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006883 * Only useful for volume controllers.
6884 * @hide
6885 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006886 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006887 public void setRingerModeInternal(int ringerMode) {
6888 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006889 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006890 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006891 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006892 }
6893 }
6894
6895 /**
6896 * Only useful for volume controllers.
6897 * @hide
6898 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006899 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006900 public int getRingerModeInternal() {
6901 try {
6902 return getService().getRingerModeInternal();
6903 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006904 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006905 }
6906 }
6907
6908 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006909 * Only useful for volume controllers.
6910 * @hide
6911 */
6912 public void setVolumePolicy(VolumePolicy policy) {
6913 try {
6914 getService().setVolumePolicy(policy);
6915 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006916 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006917 }
6918 }
6919
6920 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006921 * Set Hdmi Cec system audio mode.
6922 *
6923 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006924 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006925 * @hide
6926 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006927 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006928 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006929 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006930 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006931 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006932 }
6933 }
6934
6935 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006936 * Returns true if Hdmi Cec system audio mode is supported.
6937 *
6938 * @hide
6939 */
6940 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006941 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006942 public boolean isHdmiSystemAudioSupported() {
6943 try {
6944 return getService().isHdmiSystemAudioSupported();
6945 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006946 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006947 }
6948 }
6949
6950 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006951 * Return codes for listAudioPorts(), createAudioPatch() ...
6952 */
6953
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006954 /** @hide */
6955 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006956 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006957 /**
6958 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006959 */
6960 public static final int ERROR = AudioSystem.ERROR;
6961 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006962 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006963 */
6964 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6965 /** @hide
6966 */
6967 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6968 /** @hide
6969 */
6970 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6971 /** @hide
6972 */
6973 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006974 /**
6975 * An error code indicating that the object reporting it is no longer valid and needs to
6976 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006977 */
6978 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6979
6980 /**
6981 * Returns a list of descriptors for all audio ports managed by the audio framework.
6982 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6983 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6984 * See AudioPort for a list of attributes of each audio port.
6985 * @param ports An AudioPort ArrayList where the list will be returned.
6986 * @hide
6987 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006988 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006989 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006990 return updateAudioPortCache(ports, null, null);
6991 }
6992
6993 /**
6994 * Returns a list of descriptors for all audio ports managed by the audio framework as
6995 * it was before the last update calback.
6996 * @param ports An AudioPort ArrayList where the list will be returned.
6997 * @hide
6998 */
6999 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
7000 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08007001 }
7002
7003 /**
7004 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
7005 * @see listAudioPorts(ArrayList<AudioPort>)
7006 * @hide
7007 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07007008 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007009 if (devices == null) {
7010 return ERROR_BAD_VALUE;
7011 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007012 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007013 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07007014 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007015 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07007016 }
7017 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08007018 }
7019
7020 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007021 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
7022 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
7023 * @hide
7024 */
7025 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
7026 if (devices == null) {
7027 return ERROR_BAD_VALUE;
7028 }
7029 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
7030 int status = updateAudioPortCache(null, null, ports);
7031 if (status == SUCCESS) {
7032 filterDevicePorts(ports, devices);
7033 }
7034 return status;
7035 }
7036
7037 private static void filterDevicePorts(ArrayList<AudioPort> ports,
7038 ArrayList<AudioDevicePort> devices) {
7039 devices.clear();
7040 for (int i = 0; i < ports.size(); i++) {
7041 if (ports.get(i) instanceof AudioDevicePort) {
7042 devices.add((AudioDevicePort)ports.get(i));
7043 }
7044 }
7045 }
7046
7047 /**
Eric Laurenta198a292014-02-18 16:26:17 -08007048 * Create a connection between two or more devices. The framework will reject the request if
7049 * device types are not compatible or the implementation does not support the requested
7050 * configuration.
7051 * NOTE: current implementation is limited to one source and one sink per patch.
7052 * @param patch AudioPatch array where the newly created patch will be returned.
7053 * As input, if patch[0] is not null, the specified patch will be replaced by the
7054 * new patch created. This avoids calling releaseAudioPatch() when modifying a
7055 * patch and allows the implementation to optimize transitions.
7056 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
7057 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
7058 *
7059 * @return - {@link #SUCCESS} if connection is successful.
7060 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
7061 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
7062 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
7063 * a patch.
7064 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7065 * - {@link #ERROR} if patch cannot be connected for any other reason.
7066 *
7067 * patch[0] contains the newly created patch
7068 * @hide
7069 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007070 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007071 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08007072 AudioPortConfig[] sources,
7073 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007074 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08007075 }
7076
7077 /**
7078 * Releases an existing audio patch connection.
7079 * @param patch The audio patch to disconnect.
7080 * @return - {@link #SUCCESS} if disconnection is successful.
7081 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
7082 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
7083 * a patch.
7084 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7085 * - {@link #ERROR} if patch cannot be released for any other reason.
7086 * @hide
7087 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007088 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007089 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007090 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08007091 }
7092
7093 /**
7094 * List all existing connections between audio ports.
7095 * @param patches An AudioPatch array where the list will be returned.
7096 * @hide
7097 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007098 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007099 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007100 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08007101 }
7102
7103 /**
7104 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
7105 * AudioGain.buildConfig()
7106 * @hide
7107 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07007108 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07007109 if (port == null || gain == null) {
7110 return ERROR_BAD_VALUE;
7111 }
7112 AudioPortConfig activeConfig = port.activeConfig();
7113 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
7114 activeConfig.channelMask(), activeConfig.format(), gain);
7115 config.mConfigMask = AudioPortConfig.GAIN;
7116 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08007117 }
7118
7119 /**
7120 * Listener registered by client to be notified upon new audio port connections,
7121 * disconnections or attributes update.
7122 * @hide
7123 */
7124 public interface OnAudioPortUpdateListener {
7125 /**
7126 * Callback method called upon audio port list update.
7127 * @param portList the updated list of audio ports
7128 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007129 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08007130
7131 /**
7132 * Callback method called upon audio patch list update.
7133 * @param patchList the updated list of audio patches
7134 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007135 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08007136
7137 /**
7138 * Callback method called when the mediaserver dies
7139 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007140 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08007141 }
7142
7143 /**
Eric Laurent700e7342014-05-02 18:33:15 -07007144 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08007145 * @hide
7146 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007147 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08007148 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007149 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08007150 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08007151 }
7152
7153 /**
Eric Laurent700e7342014-05-02 18:33:15 -07007154 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08007155 * @hide
7156 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007157 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08007158 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08007159 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08007160 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007161
7162 //
7163 // AudioPort implementation
7164 //
7165
Cole Faust7da659b2022-10-15 21:33:29 -07007166 private static final int AUDIOPORT_GENERATION_INIT = 0;
7167 private static Object sAudioPortGenerationLock = new Object();
7168 @GuardedBy("sAudioPortGenerationLock")
7169 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
7170 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
7171 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
7172 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07007173
Eric Laurentf076db42015-01-14 13:23:27 -08007174 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07007175 int generation;
Cole Faust7da659b2022-10-15 21:33:29 -07007176 synchronized (sAudioPortGenerationLock) {
Eric Laurentf076db42015-01-14 13:23:27 -08007177 generation = sAudioPortGeneration;
7178 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07007179 }
7180 return generation;
7181 }
7182
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007183 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
7184 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007185 sAudioPortEventHandler.init();
Cole Faust7da659b2022-10-15 21:33:29 -07007186 synchronized (sAudioPortGenerationLock) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007187
Eric Laurentf076db42015-01-14 13:23:27 -08007188 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007189 int[] patchGeneration = new int[1];
7190 int[] portGeneration = new int[1];
7191 int status;
7192 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
7193 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
7194
7195 do {
7196 newPorts.clear();
7197 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07007198 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09007199 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07007200 return status;
7201 }
7202 newPatches.clear();
7203 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07007204 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09007205 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07007206 return status;
7207 }
jiabinc4ecaa52017-09-26 14:28:41 -07007208 // Loop until patch generation is the same as port generation unless audio ports
7209 // and audio patches are not null.
7210 } while (patchGeneration[0] != portGeneration[0]
7211 && (ports == null || patches == null));
7212 // If the patch generation doesn't equal port generation, return ERROR here in case
7213 // of mismatch between audio ports and audio patches.
7214 if (patchGeneration[0] != portGeneration[0]) {
7215 return ERROR;
7216 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007217
7218 for (int i = 0; i < newPatches.size(); i++) {
7219 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07007220 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
7221 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07007222 newPatches.get(i).sources()[j] = portCfg;
7223 }
7224 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07007225 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
7226 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07007227 newPatches.get(i).sinks()[j] = portCfg;
7228 }
7229 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09007230 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
7231 AudioPatch newPatch = i.next();
7232 boolean hasInvalidPort = false;
7233 for (AudioPortConfig portCfg : newPatch.sources()) {
7234 if (portCfg == null) {
7235 hasInvalidPort = true;
7236 break;
7237 }
7238 }
7239 for (AudioPortConfig portCfg : newPatch.sinks()) {
7240 if (portCfg == null) {
7241 hasInvalidPort = true;
7242 break;
7243 }
7244 }
7245 if (hasInvalidPort) {
7246 // Temporarily remove patches with invalid ports. One who created the patch
7247 // is responsible for dealing with the port change.
7248 i.remove();
7249 }
7250 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007251
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007252 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08007253 sAudioPortsCached = newPorts;
7254 sAudioPatchesCached = newPatches;
7255 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07007256 }
7257 if (ports != null) {
7258 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08007259 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07007260 }
7261 if (patches != null) {
7262 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08007263 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07007264 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007265 if (previousPorts != null) {
7266 previousPorts.clear();
7267 previousPorts.addAll(sPreviousAudioPortsCached);
7268 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007269 }
7270 return SUCCESS;
7271 }
7272
Eric Laurentf076db42015-01-14 13:23:27 -08007273 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007274 AudioPort port = portCfg.port();
7275 int k;
7276 for (k = 0; k < ports.size(); k++) {
7277 // compare handles because the port returned by JNI is not of the correct
7278 // subclass
7279 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007280 port = ports.get(k);
7281 break;
7282 }
7283 }
7284 if (k == ports.size()) {
Darwin Huangbb111732022-10-21 13:14:32 +00007285 // This can happen in case of stale audio patch referring to a removed device and is
7286 // handled by the caller.
Eric Laurentb69681c2014-05-19 19:02:51 -07007287 return null;
7288 }
7289 AudioGainConfig gainCfg = portCfg.gain();
7290 if (gainCfg != null) {
7291 AudioGain gain = port.gain(gainCfg.index());
7292 gainCfg = gain.buildConfig(gainCfg.mode(),
7293 gainCfg.channelMask(),
7294 gainCfg.values(),
7295 gainCfg.rampDurationMs());
7296 }
7297 return port.buildConfig(portCfg.samplingRate(),
7298 portCfg.channelMask(),
7299 portCfg.format(),
7300 gainCfg);
7301 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007302
7303 private OnAmPortUpdateListener mPortListener = null;
7304
7305 /**
7306 * The message sent to apps when the contents of the device list changes if they provide
Paul Wang9b2d0482022-05-17 10:18:01 +00007307 * a {@link Handler} object to {@link registerAudioDeviceCallback}.
Paul McLeane3383cc2015-05-08 11:41:20 -07007308 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07007309 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
7310 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
7311 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07007312
Paul McLean8e6c9f42015-05-19 11:13:41 -07007313 /**
7314 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
7315 */
Jack He89f97982018-05-02 19:10:56 -07007316 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07007317 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07007318
7319 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007320 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
7321 * the results list to only those device types they are interested in.
7322 */
7323 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07007324 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7325 * source (i.e. input) audio devices.
7326 */
7327 public static final int GET_DEVICES_INPUTS = 0x0001;
7328
7329 /**
7330 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7331 * sink (i.e. output) audio devices.
7332 */
7333 public static final int GET_DEVICES_OUTPUTS = 0x0002;
7334
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007335 /** @hide */
7336 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
7337 GET_DEVICES_INPUTS,
7338 GET_DEVICES_OUTPUTS }
7339 )
7340 @Retention(RetentionPolicy.SOURCE)
7341 public @interface AudioDeviceRole {}
7342
Paul McLeane3383cc2015-05-08 11:41:20 -07007343 /**
7344 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
7345 * source and sink devices.
7346 */
7347 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
7348
7349 /**
7350 * Determines if a given AudioDevicePort meets the specified filter criteria.
7351 * @param port The port to test.
7352 * @param flags A set of bitflags specifying the criteria to test.
7353 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
7354 **/
7355 private static boolean checkFlags(AudioDevicePort port, int flags) {
7356 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
7357 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
7358 }
7359
Paul McLean11354572015-08-07 12:50:48 -06007360 private static boolean checkTypes(AudioDevicePort port) {
7361 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07007362 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06007363 }
7364
Paul McLeane3383cc2015-05-08 11:41:20 -07007365 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007366 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
7367 * currently connected to the system and meeting the criteria specified in the
7368 * <code>flags</code> parameter.
jiabin83221092023-01-10 00:15:47 +00007369 * Notes that Android audio framework only support one device per device type. In that case,
7370 * if there are multiple audio device with the same device type connected to the Android device,
7371 * only the last reported device will be known by Android audio framework and returned by this
7372 * API.
Paul McLeane3383cc2015-05-08 11:41:20 -07007373 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007374 * @see #GET_DEVICES_OUTPUTS
7375 * @see #GET_DEVICES_INPUTS
7376 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07007377 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7378 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007379 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007380 return getDevicesStatic(flags);
7381 }
7382
Paul McLean8e6c9f42015-05-19 11:13:41 -07007383 /**
7384 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
7385 * objects from the current (internal) AudioDevicePort list.
7386 */
Paul McLean03346882015-05-12 15:36:56 -07007387 private static AudioDeviceInfo[]
7388 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007389
Paul McLean8e6c9f42015-05-19 11:13:41 -07007390 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07007391 int numRecs = 0;
7392 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007393 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007394 numRecs++;
7395 }
7396 }
7397
Paul McLean8e6c9f42015-05-19 11:13:41 -07007398 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07007399 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
7400 int slot = 0;
7401 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007402 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007403 deviceList[slot++] = new AudioDeviceInfo(port);
7404 }
7405 }
7406
7407 return deviceList;
7408 }
7409
Paul McLean03346882015-05-12 15:36:56 -07007410 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07007411 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
7412 * the add/remove callback mechanism to provide a list of the newly added or removed devices
7413 * rather than the whole list and make the app figure it out.
7414 * Note that calling this method with:
7415 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
7416 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07007417 */
7418 private static AudioDeviceInfo[] calcListDeltas(
7419 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
7420
7421 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
7422
7423 AudioDevicePort cur_port = null;
7424 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
7425 boolean cur_port_found = false;
7426 cur_port = ports_B.get(cur_index);
7427 for (int prev_index = 0;
7428 prev_index < ports_A.size() && !cur_port_found;
7429 prev_index++) {
7430 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
7431 }
7432
7433 if (!cur_port_found) {
7434 delta_ports.add(cur_port);
7435 }
7436 }
7437
7438 return infoListFromPortList(delta_ports, flags);
7439 }
7440
Paul McLeane3383cc2015-05-08 11:41:20 -07007441 /**
Paul McLean03346882015-05-12 15:36:56 -07007442 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
7443 * connected to the system and meeting the criteria specified in the <code>flags</code>
7444 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007445 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07007446 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007447 * @see #GET_DEVICES_OUTPUTS
7448 * @see #GET_DEVICES_INPUTS
7449 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07007450 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7451 * @hide
7452 */
7453 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
7454 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
7455 int status = AudioManager.listAudioDevicePorts(ports);
7456 if (status != AudioManager.SUCCESS) {
7457 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07007458 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07007459 }
7460
7461 return infoListFromPortList(ports, flags);
7462 }
7463
7464 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007465 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
7466 * @param portId The audio port ID to look up for.
7467 * @param flags A set of bitflags specifying the criteria to test.
7468 * @see #GET_DEVICES_OUTPUTS
7469 * @see #GET_DEVICES_INPUTS
7470 * @see #GET_DEVICES_ALL
7471 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
7472 * @hide
7473 */
7474 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
7475 if (portId == 0) {
7476 return null;
7477 }
7478 AudioDeviceInfo[] devices = getDevicesStatic(flags);
7479 for (AudioDeviceInfo device : devices) {
7480 if (device.getId() == portId) {
7481 return device;
7482 }
7483 }
7484 return null;
7485 }
7486
7487 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007488 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07007489 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007490 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
7491 * notifications.
7492 * @param handler Specifies the {@link Handler} object for the thread on which to execute
7493 * the callback. If <code>null</code>, the {@link Handler} associated with the main
7494 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07007495 */
Paul McLean03346882015-05-12 15:36:56 -07007496 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08007497 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07007498 synchronized (mDeviceCallbacks) {
7499 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007500 if (mDeviceCallbacks.size() == 0) {
7501 if (mPortListener == null) {
7502 mPortListener = new OnAmPortUpdateListener();
7503 }
7504 registerAudioPortUpdateListener(mPortListener);
7505 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007506 NativeEventHandlerDelegate delegate =
7507 new NativeEventHandlerDelegate(callback, handler);
7508 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07007509 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07007510 }
7511 }
7512 }
7513
7514 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007515 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07007516 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007517 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08007518 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07007519 */
Paul McLean03346882015-05-12 15:36:56 -07007520 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
7521 synchronized (mDeviceCallbacks) {
7522 if (mDeviceCallbacks.containsKey(callback)) {
7523 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07007524 if (mDeviceCallbacks.size() == 0) {
7525 unregisterAudioPortUpdateListener(mPortListener);
7526 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007527 }
7528 }
7529 }
7530
jiabinc0f49442018-01-05 10:23:50 -08007531 /**
7532 * Set port id for microphones by matching device type and address.
7533 * @hide
7534 */
7535 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
7536 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
7537 for (int i = microphones.size() - 1; i >= 0; i--) {
7538 boolean foundPortId = false;
7539 for (AudioDeviceInfo device : devices) {
7540 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
7541 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
7542 microphones.get(i).setId(device.getId());
7543 foundPortId = true;
7544 break;
7545 }
7546 }
7547 if (!foundPortId) {
7548 Log.i(TAG, "Failed to find port id for device with type:"
7549 + microphones.get(i).getType() + " address:"
7550 + microphones.get(i).getAddress());
7551 microphones.remove(i);
7552 }
7553 }
7554 }
7555
7556 /**
jiabin589a2362018-02-22 16:21:53 -08007557 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
7558 * @hide
7559 */
7560 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
7561 int deviceType = deviceInfo.getType();
7562 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
7563 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
7564 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
7565 : MicrophoneInfo.LOCATION_PERIPHERAL;
7566 MicrophoneInfo microphone = new MicrophoneInfo(
7567 deviceInfo.getPort().name() + deviceInfo.getId(),
7568 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
7569 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
7570 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
7571 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
7572 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
7573 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
7574 microphone.setId(deviceInfo.getId());
7575 return microphone;
7576 }
7577
7578 /**
jiabind0be5b22018-04-10 14:10:04 -07007579 * Add {@link MicrophoneInfo} by device information while filtering certain types.
7580 */
7581 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
7582 HashSet<Integer> filterTypes) {
7583 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
7584 for (AudioDeviceInfo device : devices) {
7585 if (filterTypes.contains(device.getType())) {
7586 continue;
7587 }
7588 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
7589 microphones.add(microphone);
7590 }
7591 }
7592
7593 /**
jiabinc0f49442018-01-05 10:23:50 -08007594 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
7595 * of all available microphones. The list is empty when no microphones are available
7596 * on the device. An error during the query will result in an IOException being thrown.
7597 *
7598 * @return a list that contains all microphones' characteristics
7599 * @throws IOException if an error occurs.
7600 */
7601 public List<MicrophoneInfo> getMicrophones() throws IOException {
7602 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
7603 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07007604 HashSet<Integer> filterTypes = new HashSet<>();
7605 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08007606 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07007607 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07007608 if (status != AudioManager.ERROR_INVALID_OPERATION) {
7609 Log.e(TAG, "getMicrophones failed:" + status);
7610 }
7611 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07007612 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
7613 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08007614 }
7615 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07007616 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
7617 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08007618 return microphones;
7619 }
7620
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007621 /**
7622 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01007623 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007624 *
7625 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01007626 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007627 * @hide
7628 */
William Escandea05cb452021-12-08 14:14:19 +01007629 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7630 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
7631 ArrayList<Integer> formatsList = new ArrayList<>();
7632 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007633
William Escandea05cb452021-12-08 14:14:19 +01007634 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
7635 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007636 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01007637 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
7638 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007639 }
7640
William Escandea05cb452021-12-08 14:14:19 +01007641 for (Integer format : formatsList) {
7642 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
7643 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
Etienne Ruffieux2c5180a2022-03-08 13:31:41 +00007644 codecConfigList.add(
7645 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007646 }
William Escandea05cb452021-12-08 14:14:19 +01007647 }
7648 return codecConfigList;
7649 }
7650
Patty Huang1dc21e12022-07-06 00:12:03 +08007651 private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
7652 @AudioSystem.BtOffloadDeviceType int deviceType) {
William Escandea05cb452021-12-08 14:14:19 +01007653 ArrayList<Integer> formatsList = new ArrayList<>();
7654 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
7655
7656 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
Patty Huang1dc21e12022-07-06 00:12:03 +08007657 deviceType, formatsList);
William Escandea05cb452021-12-08 14:14:19 +01007658 if (status != AudioManager.SUCCESS) {
7659 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08007660 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007661 }
William Escandea05cb452021-12-08 14:14:19 +01007662
7663 for (Integer format : formatsList) {
7664 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
7665 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
7666 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
7667 .setCodecType(btLeAudioCodec)
7668 .build());
7669 }
7670 }
7671 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007672 }
7673
Patty Huang1dc21e12022-07-06 00:12:03 +08007674 /**
7675 * Returns a list of audio formats that corresponds to encoding formats
7676 * supported on offload path for Le audio playback.
7677 *
7678 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
7679 * supported for offload Le Audio playback
7680 * @hide
7681 */
7682 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7683 @NonNull
7684 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
7685 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
7686 }
7687
7688 /**
7689 * Returns a list of audio formats that corresponds to encoding formats
7690 * supported on offload path for Le Broadcast playback.
7691 *
7692 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
7693 * supported for offload Le Broadcast playback
7694 * @hide
7695 */
7696 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7697 @NonNull
7698 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
7699 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
7700 }
7701
Paul McLeancbeb8a22015-06-10 08:21:27 -07007702 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
7703 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
7704 // of the ports that exist at the time of the last notification.
7705 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
7706
Paul McLeane3383cc2015-05-08 11:41:20 -07007707 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007708 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07007709 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07007710 */
jiabin8c3a7672018-05-22 15:44:21 -07007711 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07007712 int status;
7713
Paul McLeancbeb8a22015-06-10 08:21:27 -07007714 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07007715 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
7716 status = AudioManager.listAudioDevicePorts(current_ports);
7717 if (status != AudioManager.SUCCESS) {
7718 return;
7719 }
7720
Paul McLeancbeb8a22015-06-10 08:21:27 -07007721 if (handler != null) {
7722 // This is the callback for the registration, so send the current list
7723 AudioDeviceInfo[] deviceList =
7724 infoListFromPortList(current_ports, GET_DEVICES_ALL);
7725 handler.sendMessage(
7726 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
7727 } else {
7728 AudioDeviceInfo[] added_devices =
7729 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
7730 AudioDeviceInfo[] removed_devices =
7731 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07007732 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07007733 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
7734 handler = mDeviceCallbacks.valueAt(i).getHandler();
7735 if (handler != null) {
7736 if (removed_devices.length != 0) {
7737 handler.sendMessage(Message.obtain(handler,
7738 MSG_DEVICES_DEVICES_REMOVED,
7739 removed_devices));
7740 }
7741 if (added_devices.length != 0) {
7742 handler.sendMessage(Message.obtain(handler,
7743 MSG_DEVICES_DEVICES_ADDED,
7744 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07007745 }
Paul McLean03346882015-05-12 15:36:56 -07007746 }
7747 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007748 }
7749 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007750
7751 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07007752 }
7753
7754 /**
7755 * Handles Port list update notifications from the AudioManager
7756 */
7757 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
7758 static final String TAG = "OnAmPortUpdateListener";
7759 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07007760 synchronized (mDeviceCallbacks) {
7761 broadcastDeviceListChange_sync(null);
7762 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007763 }
7764
7765 /**
7766 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007767 * Note: We don't do anything with Patches at this time, so ignore this notification.
7768 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07007769 */
7770 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
7771
7772 /**
7773 * Callback method called when the mediaserver dies
7774 */
7775 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07007776 synchronized (mDeviceCallbacks) {
7777 broadcastDeviceListChange_sync(null);
7778 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007779 }
7780 }
7781
Eric Laurent1d3cdce2018-01-20 10:31:21 -08007782
7783 /**
7784 * @hide
7785 * Abstract class to receive event notification about audioserver process state.
7786 */
7787 @SystemApi
7788 public abstract static class AudioServerStateCallback {
7789 public void onAudioServerDown() { }
7790 public void onAudioServerUp() { }
7791 }
7792
7793 private Executor mAudioServerStateExec;
7794 private AudioServerStateCallback mAudioServerStateCb;
7795 private final Object mAudioServerStateCbLock = new Object();
7796
7797 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
7798 new IAudioServerStateDispatcher.Stub() {
7799 @Override
7800 public void dispatchAudioServerStateChange(boolean state) {
7801 Executor exec;
7802 AudioServerStateCallback cb;
7803
7804 synchronized (mAudioServerStateCbLock) {
7805 exec = mAudioServerStateExec;
7806 cb = mAudioServerStateCb;
7807 }
7808
7809 if ((exec == null) || (cb == null)) {
7810 return;
7811 }
7812 if (state) {
7813 exec.execute(() -> cb.onAudioServerUp());
7814 } else {
7815 exec.execute(() -> cb.onAudioServerDown());
7816 }
7817 }
7818 };
7819
7820 /**
7821 * @hide
7822 * Registers a callback for notification of audio server state changes.
7823 * @param executor {@link Executor} to handle the callbacks
7824 * @param stateCallback the callback to receive the audio server state changes
7825 * To remove the callabck, pass a null reference for both executor and stateCallback.
7826 */
7827 @SystemApi
7828 public void setAudioServerStateCallback(@NonNull Executor executor,
7829 @NonNull AudioServerStateCallback stateCallback) {
7830 if (stateCallback == null) {
7831 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
7832 }
7833 if (executor == null) {
7834 throw new IllegalArgumentException(
7835 "Illegal null Executor for the AudioServerStateCallback");
7836 }
7837
7838 synchronized (mAudioServerStateCbLock) {
7839 if (mAudioServerStateCb != null) {
7840 throw new IllegalStateException(
7841 "setAudioServerStateCallback called with already registered callabck");
7842 }
7843 final IAudioService service = getService();
7844 try {
7845 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7846 } catch (RemoteException e) {
7847 throw e.rethrowFromSystemServer();
7848 }
7849 mAudioServerStateExec = executor;
7850 mAudioServerStateCb = stateCallback;
7851 }
7852 }
7853
7854 /**
7855 * @hide
7856 * Unregisters the callback for notification of audio server state changes.
7857 */
7858 @SystemApi
7859 public void clearAudioServerStateCallback() {
7860 synchronized (mAudioServerStateCbLock) {
7861 if (mAudioServerStateCb != null) {
7862 final IAudioService service = getService();
7863 try {
7864 service.unregisterAudioServerStateDispatcher(
7865 mAudioServerStateDispatcher);
7866 } catch (RemoteException e) {
7867 throw e.rethrowFromSystemServer();
7868 }
7869 }
7870 mAudioServerStateExec = null;
7871 mAudioServerStateCb = null;
7872 }
7873 }
7874
7875 /**
7876 * @hide
7877 * Checks if native audioservice is running or not.
7878 * @return true if native audioservice runs, false otherwise.
7879 */
7880 @SystemApi
7881 public boolean isAudioServerRunning() {
7882 final IAudioService service = getService();
7883 try {
7884 return service.isAudioServerRunning();
7885 } catch (RemoteException e) {
7886 throw e.rethrowFromSystemServer();
7887 }
7888 }
7889
jiabin39940752018-04-02 18:18:45 -07007890 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007891 * Sets the surround sound mode.
7892 *
7893 * @return true if successful, otherwise false
7894 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00007895 @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
Kriti Dang527e66c2021-03-04 10:37:22 +01007896 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7897 try {
7898 return getService().setEncodedSurroundMode(mode);
7899 } catch (RemoteException e) {
7900 throw e.rethrowFromSystemServer();
7901 }
7902 }
7903
7904 /**
7905 * Gets the surround sound mode.
7906 *
7907 * @return true if successful, otherwise false
7908 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007909 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7910 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007911 return getService().getEncodedSurroundMode(
7912 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007913 } catch (RemoteException e) {
7914 throw e.rethrowFromSystemServer();
7915 }
7916 }
7917
7918 /**
jiabin39940752018-04-02 18:18:45 -07007919 * @hide
7920 * Returns all surround formats.
7921 * @return a map where the key is a surround format and
7922 * the value indicates the surround format is enabled or not
7923 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007924 @TestApi
7925 @NonNull
jiabin39940752018-04-02 18:18:45 -07007926 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007927 try {
7928 return getService().getSurroundFormats();
7929 } catch (RemoteException e) {
7930 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007931 }
jiabin39940752018-04-02 18:18:45 -07007932 }
7933
7934 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007935 * Sets and persists a certain surround format as enabled or not.
7936 * <p>
7937 * This API is called by TvSettings surround sound menu when user enables or disables a
7938 * surround sound format. This setting is persisted as global user setting.
7939 * Applications should revert their changes to surround sound settings unless they intend to
7940 * modify the global user settings across all apps. The framework does not auto-revert an
7941 * application's settings after a lifecycle event. Audio focus is not required to apply these
7942 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007943 *
jiabin39940752018-04-02 18:18:45 -07007944 * @param enabled the required surround format state, true for enabled, false for disabled
7945 * @return true if successful, otherwise false
7946 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00007947 @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007948 public boolean setSurroundFormatEnabled(
7949 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007950 try {
7951 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7952 } catch (RemoteException e) {
7953 throw e.rethrowFromSystemServer();
7954 }
7955 }
7956
7957 /**
7958 * Gets whether a certain surround format is enabled or not.
7959 * @param audioFormat a surround format
7960 *
7961 * @return whether the required surround format is enabled
7962 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007963 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7964 try {
7965 return getService().isSurroundFormatEnabled(audioFormat);
7966 } catch (RemoteException e) {
7967 throw e.rethrowFromSystemServer();
7968 }
jiabin39940752018-04-02 18:18:45 -07007969 }
7970
7971 /**
7972 * @hide
7973 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007974 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007975 *
Kriti Dang01924232021-03-02 13:51:09 +01007976 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007977 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007978 @TestApi
7979 @NonNull
7980 public List<Integer> getReportedSurroundFormats() {
7981 try {
7982 return getService().getReportedSurroundFormats();
7983 } catch (RemoteException e) {
7984 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007985 }
jiabin39940752018-04-02 18:18:45 -07007986 }
7987
jiabin66f9e722018-11-02 16:20:19 -07007988 /**
7989 * Return if audio haptic coupled playback is supported or not.
7990 *
7991 * @return whether audio haptic playback supported.
7992 */
7993 public static boolean isHapticPlaybackSupported() {
7994 return AudioSystem.isHapticPlaybackSupported();
7995 }
7996
François Gaffie0699fec2018-07-09 14:35:10 +02007997 /**
7998 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08007999 * Indicates whether a platform supports the Ultrasound feature which covers the playback
8000 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
8001 * usage will be
8002 * To start the Ultrasound playback:
8003 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
8004 * To start the Ultrasound capture:
8005 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
8006 *
8007 * @return whether the ultrasound feature is supported, true when platform supports both
8008 * Ultrasound playback and capture, false otherwise.
8009 */
8010 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008011 @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND)
Carter Hsu3ea30de42022-02-15 15:59:00 +08008012 public boolean isUltrasoundSupported() {
8013 try {
8014 return getService().isUltrasoundSupported();
8015 } catch (RemoteException e) {
8016 throw e.rethrowFromSystemServer();
8017 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08008018 }
8019
8020 /**
8021 * @hide
Atneya Naireeab0a72022-12-15 09:32:51 -08008022 * Indicates whether the platform supports capturing content from the hotword recognition
8023 * pipeline. To capture content of this type, create an AudioRecord with
8024 * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}.
8025 * @param lookbackAudio Query if the hotword stream additionally supports providing buffered
8026 * audio prior to stream open.
8027 * @return True if the platform supports capturing hotword content, and if lookbackAudio
8028 * is true, if it additionally supports capturing buffered hotword content prior to stream
8029 * open. False otherwise.
8030 */
8031 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008032 @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
Atneya Naireeab0a72022-12-15 09:32:51 -08008033 public boolean isHotwordStreamSupported(boolean lookbackAudio) {
8034 try {
8035 return getService().isHotwordStreamSupported(lookbackAudio);
8036 } catch (RemoteException e) {
8037 return false;
8038 }
8039 }
8040
8041 /**
8042 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02008043 * Introspection API to retrieve audio product strategies.
8044 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
8045 * audio product strategies, which is indexed by a weakly typed index in order to be extended
8046 * by OEM without any needs of AOSP patches.
8047 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
8048 * strategy refered either by its index or human readable string. It will allow clients
8049 * application to start streaming data using these {@link AudioAttributes} on the selected
8050 * device by Audio Policy Engine.
8051 * @return a (possibly zero-length) array of
8052 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
8053 */
8054 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07008055 @NonNull
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008056 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07008057 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02008058 final IAudioService service = getService();
8059 try {
8060 return service.getAudioProductStrategies();
8061 } catch (RemoteException e) {
8062 throw e.rethrowFromSystemServer();
8063 }
8064 }
8065
François Gaffieadcd00a2018-09-18 17:06:26 +02008066 /**
8067 * @hide
8068 * Introspection API to retrieve audio volume groups.
8069 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
8070 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008071 * @return a (possibly zero-length) List of
8072 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02008073 */
8074 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008075 @NonNull
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008076 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008077 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02008078 final IAudioService service = getService();
8079 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008080 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02008081 } catch (RemoteException e) {
8082 throw e.rethrowFromSystemServer();
8083 }
François Gaffieadcd00a2018-09-18 17:06:26 +02008084 }
8085
8086 /**
8087 * @hide
8088 * Callback registered by client to be notified upon volume group change.
8089 */
8090 @SystemApi
8091 public abstract static class VolumeGroupCallback {
8092 /**
8093 * Callback method called upon audio volume group change.
8094 * @param group the group for which the volume has changed
8095 */
8096 public void onAudioVolumeGroupChanged(int group, int flags) {}
8097 }
8098
8099 /**
8100 * @hide
8101 * Register an audio volume group change listener.
8102 * @param callback the {@link VolumeGroupCallback} to register
8103 */
8104 @SystemApi
8105 public void registerVolumeGroupCallback(
8106 @NonNull Executor executor,
8107 @NonNull VolumeGroupCallback callback) {
8108 Preconditions.checkNotNull(executor, "executor must not be null");
8109 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8110 sAudioAudioVolumeGroupChangedHandler.init();
8111 // TODO: make use of executor
8112 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
8113 }
8114
8115 /**
8116 * @hide
8117 * Unregister an audio volume group change listener.
8118 * @param callback the {@link VolumeGroupCallback} to unregister
8119 */
8120 @SystemApi
8121 public void unregisterVolumeGroupCallback(
8122 @NonNull VolumeGroupCallback callback) {
8123 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8124 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
8125 }
jiabin39940752018-04-02 18:18:45 -07008126
jiabinad225202019-03-20 15:22:50 -07008127 /**
8128 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07008129 *
8130 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07008131 * @param uri the {@link Uri} of the asset.
8132 * @return true if the assert contains haptic channels.
8133 * @hide
8134 */
jiabincfcf1032021-07-01 16:30:50 -07008135 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
8136 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07008137 try {
jiabincfcf1032021-07-01 16:30:50 -07008138 extractor.setDataSource(context, uri, null);
8139 for (int i = 0; i < extractor.getTrackCount(); i++) {
8140 MediaFormat format = extractor.getTrackFormat(i);
8141 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
8142 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
8143 return true;
8144 }
8145 }
8146 } catch (IOException e) {
8147 Log.e(TAG, "hasHapticChannels failure:" + e);
8148 }
8149 return false;
8150 }
8151
8152 /**
8153 * Return if an asset contains haptic channels or not.
8154 *
8155 * @param context the {@link Context} to resolve the uri.
8156 * @param uri the {@link Uri} of the asset.
8157 * @return true if the assert contains haptic channels.
8158 * @hide
8159 */
8160 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
8161 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07008162
jiabincfcf1032021-07-01 16:30:50 -07008163 if (context != null) {
8164 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07008165 }
8166
8167 Context cachedContext = sContext.get();
8168 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07008169 if (DEBUG) {
8170 Log.d(TAG, "Try to use static context to query if having haptic channels");
8171 }
jiabin0f3339c2021-07-09 11:50:07 -07008172 return hasHapticChannelsImpl(cachedContext, uri);
8173 }
8174
8175 // Try with audio service context, this may fail to get correct result.
8176 if (DEBUG) {
8177 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
8178 }
8179 try {
8180 return getService().hasHapticChannels(uri);
8181 } catch (RemoteException e) {
8182 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07008183 }
8184 }
8185
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07008186 /**
8187 * Set whether or not there is an active RTT call.
8188 * This method should be called by Telecom service.
8189 * @hide
8190 * TODO: make this a @SystemApi
8191 */
8192 public static void setRttEnabled(boolean rttEnabled) {
8193 try {
8194 getService().setRttEnabled(rttEnabled);
8195 } catch (RemoteException e) {
8196 throw e.rethrowFromSystemServer();
8197 }
8198 }
8199
Jin Seok Park16aeba382020-08-06 12:52:54 +09008200 /**
8201 * Adjusts the volume of the most relevant stream, or the given fallback
8202 * stream.
8203 * <p>
8204 * This method should only be used by applications that replace the
8205 * platform-wide management of audio settings or the main telephony
8206 * application.
8207 * <p>
8208 * This method has no effect if the device implements a fixed volume policy
8209 * as indicated by {@link #isVolumeFixed()}.
8210 * <p>This API checks if the caller has the necessary permissions based on the provided
8211 * component name, uid, and pid values.
8212 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
8213 *
8214 * @param suggestedStreamType The stream type that will be used if there
8215 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
8216 * valid here.
8217 * @param direction The direction to adjust the volume. One of
8218 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
8219 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
8220 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
8221 * @param flags One or more flags.
8222 * @param packageName the package name of client application
8223 * @param uid the uid of client application
8224 * @param pid the pid of client application
8225 * @param targetSdkVersion the target sdk version of client application
8226 * @see #adjustVolume(int, int)
8227 * @see #adjustStreamVolume(int, int, int)
8228 * @see #setStreamVolume(int, int, int)
8229 * @see #isVolumeFixed()
8230 *
8231 * @hide
8232 */
8233 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8234 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
8235 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8236 try {
8237 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
8238 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8239 } catch (RemoteException e) {
8240 throw e.rethrowFromSystemServer();
8241 }
8242 }
8243
8244 /**
8245 * Adjusts the volume of a particular stream by one step in a direction.
8246 * <p>
8247 * This method should only be used by applications that replace the platform-wide
8248 * management of audio settings or the main telephony application.
8249 * <p>This method has no effect if the device implements a fixed volume policy
8250 * as indicated by {@link #isVolumeFixed()}.
8251 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
8252 * unless the app has been granted Do Not Disturb Access.
8253 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8254 * <p>This API checks if the caller has the necessary permissions based on the provided
8255 * component name, uid, and pid values.
8256 * See {@link #adjustStreamVolume(int, int, int)}.
8257 *
8258 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
8259 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
8260 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
8261 * @param direction The direction to adjust the volume. One of
8262 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
8263 * {@link #ADJUST_SAME}.
8264 * @param flags One or more flags.
8265 * @param packageName the package name of client application
8266 * @param uid the uid of client application
8267 * @param pid the pid of client application
8268 * @param targetSdkVersion the target sdk version of client application
8269 * @see #adjustVolume(int, int)
8270 * @see #setStreamVolume(int, int, int)
8271 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
8272 * and the caller is not granted notification policy access.
8273 *
8274 * @hide
8275 */
8276 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8277 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
8278 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8279 try {
8280 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
8281 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8282 } catch (RemoteException e) {
8283 throw e.rethrowFromSystemServer();
8284 }
8285 }
8286
8287 /**
8288 * Sets the volume index for a particular stream.
8289 * <p>This method has no effect if the device implements a fixed volume policy
8290 * as indicated by {@link #isVolumeFixed()}.
8291 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
8292 * the app has been granted Do Not Disturb Access.
8293 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8294 * <p>This API checks if the caller has the necessary permissions based on the provided
8295 * component name, uid, and pid values.
8296 * See {@link #setStreamVolume(int, int, int)}.
8297 *
8298 * @param streamType The stream whose volume index should be set.
8299 * @param index The volume index to set. See
8300 * {@link #getStreamMaxVolume(int)} for the largest valid value.
8301 * @param flags One or more flags.
8302 * @param packageName the package name of client application
8303 * @param uid the uid of client application
8304 * @param pid the pid of client application
8305 * @param targetSdkVersion the target sdk version of client application
8306 * @see #getStreamMaxVolume(int)
8307 * @see #getStreamVolume(int)
8308 * @see #isVolumeFixed()
8309 * @throws SecurityException if the volume change triggers a Do Not Disturb change
8310 * and the caller is not granted notification policy access.
8311 *
8312 * @hide
8313 */
8314 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8315 public void setStreamVolumeForUid(int streamType, int index, int flags,
8316 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8317 try {
8318 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
8319 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8320 } catch (RemoteException e) {
8321 throw e.rethrowFromSystemServer();
8322 }
8323 }
8324
8325
hjin81.lee4e984e52019-12-05 14:34:52 +09008326 /** @hide
8327 * TODO: make this a @SystemApi */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008328 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
hjin81.lee4e984e52019-12-05 14:34:52 +09008329 public void setMultiAudioFocusEnabled(boolean enabled) {
8330 try {
8331 getService().setMultiAudioFocusEnabled(enabled);
8332 } catch (RemoteException e) {
8333 throw e.rethrowFromSystemServer();
8334 }
8335 }
8336
Eric Laurent43a78de2020-07-24 17:11:15 -07008337
8338 /**
8339 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
8340 * For more details on Hardware A/V synchronization please refer to
8341 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
8342 * media tunneling documentation</a>.
8343 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
8344 * @return the HW A/V sync ID for this audio session (an integer different from 0).
8345 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
8346 */
8347 public int getAudioHwSyncForSession(int sessionId) {
8348 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
8349 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
8350 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
8351 }
8352 return hwSyncId;
8353 }
8354
Eric Laurentb36d4a12020-10-09 09:52:49 -07008355 /**
8356 * Selects the audio device that should be used for communication use cases, for instance voice
8357 * or video calls. This method can be used by voice or video chat applications to select a
8358 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01008359 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
Eric Laurent6aa23612022-11-18 16:08:20 +01008360 * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role
8361 * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching
8362 * source device is selected automatically by the platform.
8363 * <p>The selection is active as long as the requesting application process lives, until
Eric Laurent7412f572021-02-11 15:10:31 +01008364 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008365 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01008366 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008367 * <p>In case of simultaneous requests by multiple applications the priority is given to the
8368 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
8369 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
8370 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
8371 * telephony application with permission
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008372 * {@link Manifest.permission#MODIFY_PHONE_STATE}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008373 * <p> If the requested devices is not currently available, the request will be rejected and
8374 * the method will return false.
8375 * <p>This API replaces the following deprecated APIs:
8376 * <ul>
8377 * <li> {@link #startBluetoothSco()}
8378 * <li> {@link #stopBluetoothSco()}
8379 * <li> {@link #setSpeakerphoneOn(boolean)}
8380 * </ul>
8381 * <h4>Example</h4>
8382 * <p>The example below shows how to enable and disable speakerphone mode.
8383 * <pre class="prettyprint">
8384 * // Get an AudioManager instance
8385 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01008386 * AudioDeviceInfo speakerDevice = null;
8387 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
8388 * for (AudioDeviceInfo device : devices) {
8389 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
8390 * speakerDevice = device;
8391 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008392 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008393 * }
8394 * if (speakerDevice != null) {
8395 * // Turn speakerphone ON.
8396 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
8397 * if (!result) {
8398 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008399 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008400 * // Turn speakerphone OFF.
8401 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008402 * }
8403 * </pre>
8404 * @param device the requested audio device.
8405 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
8406 * @throws IllegalArgumentException If an invalid device is specified.
8407 */
Eric Laurent7412f572021-02-11 15:10:31 +01008408 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008409 Objects.requireNonNull(device);
8410 try {
8411 if (device.getId() == 0) {
Eric Laurentc18e5a12023-01-20 19:30:09 +01008412 Log.w(TAG, "setCommunicationDevice: device not found: " + device);
8413 return false;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008414 }
Eric Laurent7412f572021-02-11 15:10:31 +01008415 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008416 } catch (RemoteException e) {
8417 throw e.rethrowFromSystemServer();
8418 }
8419 }
8420
8421 /**
8422 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01008423 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008424 */
Eric Laurent7412f572021-02-11 15:10:31 +01008425 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008426 try {
Eric Laurent7412f572021-02-11 15:10:31 +01008427 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07008428 } catch (RemoteException e) {
8429 throw e.rethrowFromSystemServer();
8430 }
8431 }
8432
8433 /**
8434 * Returns currently selected audio device for communication.
8435 * <p>This API replaces the following deprecated APIs:
8436 * <ul>
8437 * <li> {@link #isBluetoothScoOn()}
8438 * <li> {@link #isSpeakerphoneOn()}
8439 * </ul>
8440 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01008441 * currently selected for communication use cases. Can be null on platforms
8442 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008443 * is used.
8444 */
8445 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01008446 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008447 try {
8448 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01008449 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
8450 } catch (RemoteException e) {
8451 throw e.rethrowFromSystemServer();
8452 }
8453 }
8454
8455 /**
8456 * Returns a list of audio devices that can be selected for communication use cases via
8457 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
8458 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
8459 */
8460 @NonNull
8461 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
8462 try {
8463 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
8464 int[] portIds = getService().getAvailableCommunicationDeviceIds();
8465 for (int portId : portIds) {
8466 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
8467 if (device == null) {
8468 continue;
8469 }
8470 devices.add(device);
8471 }
8472 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008473 } catch (RemoteException e) {
8474 throw e.rethrowFromSystemServer();
8475 }
8476 }
8477
8478 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01008479 * Returns a list of direct {@link AudioProfile} that are supported for the specified
8480 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
8481 * is possible.
8482 *
8483 * <p>Direct playback means that the audio stream is not resampled or downmixed
8484 * by the framework. Checking for direct support can help the app select the representation
8485 * of audio content that most closely matches the capabilities of the device and peripherals
8486 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
8487 * or mixed with other streams, if needed.
8488 * <p>When using this information to inform your application which audio format to play,
8489 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
8490 * @param attributes a non-null {@link AudioAttributes} instance.
8491 * @return a list of {@link AudioProfile}
8492 */
8493 @NonNull
8494 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
8495 Objects.requireNonNull(attributes);
8496 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
8497 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
8498 if (status != SUCCESS) {
8499 Log.w(TAG, "getDirectProfilesForAttributes failed.");
8500 return new ArrayList<>();
8501 }
8502 return audioProfilesList;
8503 }
8504
8505 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008506 * @hide
8507 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
8508 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
8509 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
8510 * The method will return null if no device of the provided type is connected.
8511 * If more than one device of the provided type is connected, an object corresponding to the
8512 * first device encountered in the enumeration list will be returned.
8513 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01008514 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008515 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
8516 * @throws IllegalArgumentException If an invalid device type is specified.
8517 */
8518 @TestApi
8519 @Nullable
8520 public static AudioDeviceInfo getDeviceInfoFromType(
8521 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01008522 return getDeviceInfoFromTypeAndAddress(deviceType, null);
8523 }
8524
Eric Laurent78eef3a2021-11-09 16:10:42 +01008525 /**
Eric Laurent7412f572021-02-11 15:10:31 +01008526 * @hide
8527 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
8528 * address provided.
8529 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
8530 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
8531 * If a null address is provided, the matching will happen on the type only.
8532 * The method will return null if no device of the provided type and address is connected.
8533 * If more than one device of the provided type is connected, an object corresponding to the
8534 * first device encountered in the enumeration list will be returned.
8535 * @param type The device device for which an <code>AudioDeviceInfo</code>
8536 * object is queried.
8537 * @param address The device address for which an <code>AudioDeviceInfo</code>
8538 * object is queried or null if requesting match on type only.
8539 * @return An AudioDeviceInfo object or null if no matching device is connected.
8540 * @throws IllegalArgumentException If an invalid device type is specified.
8541 */
8542 @Nullable
8543 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
8544 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008545 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01008546 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008547 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01008548 if (device.getType() == type) {
8549 deviceForType = device;
8550 if (address == null || address.equals(device.getAddress())) {
8551 return device;
8552 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008553 }
8554 }
Eric Laurent7412f572021-02-11 15:10:31 +01008555 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008556 }
8557
8558 /**
8559 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01008560 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008561 */
8562 public interface OnCommunicationDeviceChangedListener {
8563 /**
8564 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01008565 * @param device the audio device requested for communication use cases.
8566 * Can be null on platforms not supporting
8567 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008568 */
8569 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
8570 }
8571
8572 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008573 * manages the OnCommunicationDeviceChangedListener listeners and the
8574 * CommunicationDeviceDispatcherStub
8575 */
8576 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
8577 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
8578 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008579 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01008580 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008581 * @param executor
8582 * @param listener
8583 */
8584 public void addOnCommunicationDeviceChangedListener(
8585 @NonNull @CallbackExecutor Executor executor,
8586 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008587 mCommDeviceChangedListenerMgr.addListener(
8588 executor, listener, "addOnCommunicationDeviceChangedListener",
8589 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008590 }
8591
8592 /**
8593 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01008594 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008595 * @param listener
8596 */
8597 public void removeOnCommunicationDeviceChangedListener(
8598 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008599 mCommDeviceChangedListenerMgr.removeListener(listener,
8600 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07008601 }
8602
Eric Laurentb36d4a12020-10-09 09:52:49 -07008603 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008604 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008605
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008606 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008607 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008608 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008609 if (register) {
8610 getService().registerCommunicationDeviceDispatcher(this);
8611 } else {
8612 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07008613 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008614 } catch (RemoteException e) {
8615 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008616 }
8617 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008618
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008619 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008620 public void dispatchCommunicationDeviceChanged(int portId) {
8621 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008622 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008623 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07008624 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008625 }
8626
Eric Laurent78eef3a2021-11-09 16:10:42 +01008627
8628 /**
8629 * @hide
8630 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
8631 * PSTN call.
8632 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
8633 * an AudioTrack for call uplink audio injection and
8634 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
8635 * an AudioRecord for call downlink audio extraction.
8636 * @return true if PSTN call audio is accessible, false otherwise.
8637 */
8638 @TestApi
8639 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008640 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01008641 public boolean isPstnCallAudioInterceptable() {
8642 final IAudioService service = getService();
8643 try {
8644 return service.isPstnCallAudioInterceptable();
8645 } catch (RemoteException e) {
8646 throw e.rethrowFromSystemServer();
8647 }
8648 }
8649
8650 /** @hide */
8651 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
8652 CALL_REDIRECT_NONE,
8653 CALL_REDIRECT_PSTN,
8654 CALL_REDIRECT_VOIP }
8655 )
8656 @Retention(RetentionPolicy.SOURCE)
8657 public @interface CallRedirectionMode {}
8658
8659 /**
8660 * Not used for call redirection
8661 * @hide
8662 */
8663 public static final int CALL_REDIRECT_NONE = 0;
8664 /**
8665 * Used to redirect PSTN call
8666 * @hide
8667 */
8668 public static final int CALL_REDIRECT_PSTN = 1;
8669 /**
8670 * Used to redirect VoIP call
8671 * @hide
8672 */
8673 public static final int CALL_REDIRECT_VOIP = 2;
8674
8675
8676 private @CallRedirectionMode int getCallRedirectMode() {
8677 int mode = getMode();
8678 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
8679 || mode == MODE_CALL_REDIRECT) {
8680 return CALL_REDIRECT_PSTN;
8681 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
8682 return CALL_REDIRECT_VOIP;
8683 }
8684 return CALL_REDIRECT_NONE;
8685 }
8686
8687 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
8688 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
8689 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
8690 throw new UnsupportedOperationException(" Unsupported encoding ");
8691 }
8692 if (format.getSampleRate() < 8000
8693 || format.getSampleRate() > 48000) {
8694 throw new UnsupportedOperationException(" Unsupported sample rate ");
8695 }
8696 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
8697 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
8698 throw new UnsupportedOperationException(" Unsupported output channel mask ");
8699 }
8700 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
8701 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
8702 throw new UnsupportedOperationException(" Unsupported input channel mask ");
8703 }
8704 }
8705
8706 class CallIRedirectionClientInfo {
8707 public WeakReference trackOrRecord;
8708 public int redirectMode;
8709 }
8710
8711 private Object mCallRedirectionLock = new Object();
8712 @GuardedBy("mCallRedirectionLock")
8713 private CallInjectionModeChangedListener mCallRedirectionModeListener;
8714 @GuardedBy("mCallRedirectionLock")
8715 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
8716
8717 /**
8718 * @hide
8719 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
8720 * This can be used for functions like call screening or call audio redirection and is reserved
8721 * to system apps with privileged permission.
8722 * @param format the desired audio format for audio playback.
8723 * p>Formats accepted are:
8724 * <ul>
8725 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8726 * <li><em>Channel mask</em> - Mono or Stereo </li>
8727 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8728 * </ul>
8729 *
8730 * @return The AudioTrack used for audio injection
8731 * @throws NullPointerException if AudioFormat argument is null.
8732 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8733 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8734 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8735 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8736 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8737 * or MODE_COMMUNICATION_REDIRECT.
8738 */
8739 @TestApi
8740 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008741 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01008742 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
8743 Objects.requireNonNull(format);
8744 checkCallRedirectionFormat(format, true /* isOutput */);
8745
8746 AudioTrack track = null;
8747 int redirectMode = getCallRedirectMode();
8748 if (redirectMode == CALL_REDIRECT_NONE) {
8749 throw new IllegalStateException(
8750 " not available in mode " + AudioSystem.modeToString(getMode()));
8751 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8752 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8753 }
8754
8755 track = new AudioTrack.Builder()
8756 .setAudioAttributes(new AudioAttributes.Builder()
8757 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
8758 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
8759 .build())
8760 .setAudioFormat(format)
8761 .setCallRedirectionMode(redirectMode)
8762 .build();
8763
8764 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
8765 synchronized (mCallRedirectionLock) {
8766 if (mCallRedirectionModeListener == null) {
8767 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8768 try {
8769 addOnModeChangedListener(
8770 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8771 } catch (Exception e) {
8772 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8773 mCallRedirectionModeListener = null;
8774 throw new UnsupportedOperationException(" Cannot register mode listener ");
8775 }
8776 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8777 }
8778 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8779 info.redirectMode = redirectMode;
8780 info.trackOrRecord = new WeakReference<AudioTrack>(track);
8781 mCallIRedirectionClients.add(info);
8782 }
8783 } else {
8784 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
8785 }
8786 return track;
8787 }
8788
8789 /**
8790 * @hide
8791 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
8792 * This can be used for functions like call screening or call audio redirection and is reserved
8793 * to system apps with privileged permission.
8794 * @param format the desired audio format for audio capture.
8795 *<p>Formats accepted are:
8796 * <ul>
8797 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8798 * <li><em>Channel mask</em> - Mono or Stereo </li>
8799 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8800 * </ul>
8801 *
8802 * @return The AudioRecord used for audio extraction
8803 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8804 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8805 * @throws NullPointerException if AudioFormat argument is null.
8806 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8807 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8808 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8809 * or MODE_COMMUNICATION_REDIRECT.
8810 */
8811 @TestApi
8812 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008813 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01008814 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
8815 Objects.requireNonNull(format);
8816 checkCallRedirectionFormat(format, false /* isOutput */);
8817
8818 AudioRecord record = null;
8819 int redirectMode = getCallRedirectMode();
8820 if (redirectMode == CALL_REDIRECT_NONE) {
8821 throw new IllegalStateException(
8822 " not available in mode " + AudioSystem.modeToString(getMode()));
8823 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8824 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8825 }
8826
8827 record = new AudioRecord.Builder()
8828 .setAudioAttributes(new AudioAttributes.Builder()
8829 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
8830 .build())
8831 .setAudioFormat(format)
8832 .setCallRedirectionMode(redirectMode)
8833 .build();
8834
8835 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
8836 synchronized (mCallRedirectionLock) {
8837 if (mCallRedirectionModeListener == null) {
8838 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8839 try {
8840 addOnModeChangedListener(
8841 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8842 } catch (Exception e) {
8843 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8844 mCallRedirectionModeListener = null;
8845 throw new UnsupportedOperationException(" Cannot register mode listener ");
8846 }
8847 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8848 }
8849 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8850 info.redirectMode = redirectMode;
8851 info.trackOrRecord = new WeakReference<AudioRecord>(record);
8852 mCallIRedirectionClients.add(info);
8853 }
8854 } else {
8855 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
8856 }
8857 return record;
8858 }
8859
8860 class CallInjectionModeChangedListener implements OnModeChangedListener {
8861 @Override
8862 public void onModeChanged(@AudioMode int mode) {
8863 synchronized (mCallRedirectionLock) {
8864 final ArrayList<CallIRedirectionClientInfo> clientInfos =
8865 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
8866 for (CallIRedirectionClientInfo info : clientInfos) {
8867 Object trackOrRecord = info.trackOrRecord.get();
8868 if (trackOrRecord != null) {
8869 if ((info.redirectMode == CALL_REDIRECT_PSTN
8870 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
8871 && mode != MODE_CALL_REDIRECT)
8872 || (info.redirectMode == CALL_REDIRECT_VOIP
8873 && mode != MODE_IN_COMMUNICATION
8874 && mode != MODE_COMMUNICATION_REDIRECT)) {
8875 if (trackOrRecord instanceof AudioTrack) {
8876 AudioTrack track = (AudioTrack) trackOrRecord;
8877 track.release();
8878 } else {
8879 AudioRecord record = (AudioRecord) trackOrRecord;
8880 record.release();
8881 }
8882 mCallIRedirectionClients.remove(info);
8883 }
8884 }
8885 }
8886 if (mCallIRedirectionClients.isEmpty()) {
8887 try {
8888 if (mCallRedirectionModeListener != null) {
8889 removeOnModeChangedListener(mCallRedirectionModeListener);
8890 }
8891 } catch (Exception e) {
8892 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
8893 } finally {
8894 mCallRedirectionModeListener = null;
8895 mCallIRedirectionClients = null;
8896 }
8897 }
8898 }
8899 }
8900 }
8901
Paul McLeane3383cc2015-05-08 11:41:20 -07008902 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008903 // audio device connection-dependent muting
8904 /**
8905 * @hide
8906 * Mute a set of playback use cases until a given audio device is connected.
8907 * Automatically unmute upon connection of the device, or after the given timeout, whichever
8908 * happens first.
8909 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
8910 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
8911 * device connects
8912 * @param device the audio device expected to connect within the timeout duration
8913 * @param timeout the maximum amount of time to wait for the device connection
8914 * @param timeUnit the unit for the timeout
8915 * @throws IllegalStateException when trying to issue the command while another is already in
8916 * progress and hasn't been cancelled by
8917 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8918 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8919 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8920 */
8921 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008922 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008923 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8924 @NonNull AudioDeviceAttributes device,
8925 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8926 if (timeout <= 0) {
8927 throw new IllegalArgumentException("Timeout must be greater than 0");
8928 }
8929 Objects.requireNonNull(usagesToMute);
8930 if (usagesToMute.length == 0) {
8931 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8932 }
8933 Objects.requireNonNull(device);
8934 Objects.requireNonNull(timeUnit);
8935 try {
8936 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8937 } catch (RemoteException e) {
8938 throw e.rethrowFromSystemServer();
8939 }
8940 }
8941
8942 /**
8943 * @hide
8944 * Query which audio device, if any, is causing some playback use cases to be muted until it
8945 * connects.
8946 * @return the audio device used in
8947 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8948 * if there is no active muting command (either because the muting command was not issued
8949 * or because it timed out)
8950 */
8951 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008952 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008953 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8954 try {
8955 return getService().getMutingExpectedDevice();
8956 } catch (RemoteException e) {
8957 throw e.rethrowFromSystemServer();
8958 }
8959 }
8960
8961 /**
8962 * @hide
8963 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8964 * command.
8965 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8966 * command was issued.
8967 * @throws IllegalStateException when trying to issue the command for a device whose connection
8968 * is not anticipated by a previous call to
8969 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8970 */
8971 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008972 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008973 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8974 throws IllegalStateException {
8975 Objects.requireNonNull(device);
8976 try {
8977 getService().cancelMuteAwaitConnection(device);
8978 } catch (RemoteException e) {
8979 throw e.rethrowFromSystemServer();
8980 }
8981 }
8982
8983 /**
8984 * @hide
8985 * A callback class to receive events about the muting and unmuting of playback use cases
8986 * conditional on the upcoming connection of an audio device.
8987 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8988 */
8989 @SystemApi
8990 public abstract static class MuteAwaitConnectionCallback {
8991
8992 /**
8993 * An event where the expected audio device connected
8994 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8995 */
8996 public static final int EVENT_CONNECTION = 1;
8997 /**
8998 * An event where the expected audio device failed connect before the timeout happened
8999 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9000 */
9001 public static final int EVENT_TIMEOUT = 2;
9002 /**
9003 * An event where the {@code muteAwaitConnection()} command
9004 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
9005 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9006 */
9007 public static final int EVENT_CANCEL = 3;
9008
9009 /** @hide */
9010 @IntDef(flag = false, prefix = "EVENT_", value = {
9011 EVENT_CONNECTION,
9012 EVENT_TIMEOUT,
9013 EVENT_CANCEL }
9014 )
9015 @Retention(RetentionPolicy.SOURCE)
9016 public @interface UnmuteEvent {}
9017
9018 /**
9019 * Called when a number of playback use cases are muted in response to a call to
9020 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
9021 * @param device the audio device whose connection is expected. Playback use cases are
9022 * unmuted when that device connects
9023 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
9024 * playback use cases.
9025 */
9026 public void onMutedUntilConnection(
9027 @NonNull AudioDeviceAttributes device,
9028 @NonNull int[] mutedUsages) {}
9029
9030 /**
9031 * Called when an event occurred that caused playback uses cases to be unmuted
9032 * @param unmuteEvent the nature of the event
9033 * @param device the device that was expected to connect
9034 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
9035 * the event occurred
9036 */
9037 public void onUnmutedEvent(
9038 @UnmuteEvent int unmuteEvent,
9039 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
9040 }
9041
9042
9043 /**
9044 * @hide
9045 * Register a callback to receive updates on the playback muting conditional on a specific
9046 * audio device connection.
9047 * @param executor the {@link Executor} handling the callback
9048 * @param callback the callback to register
9049 */
9050 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009051 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009052 public void registerMuteAwaitConnectionCallback(
9053 @NonNull @CallbackExecutor Executor executor,
9054 @NonNull MuteAwaitConnectionCallback callback) {
9055 synchronized (mMuteAwaitConnectionListenerLock) {
9056 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9057 MuteAwaitConnectionDispatcherStub> res =
9058 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
9059 executor, callback, mMuteAwaitConnectionListeners,
9060 mMuteAwaitConnDispatcherStub,
9061 () -> new MuteAwaitConnectionDispatcherStub(),
9062 stub -> stub.register(true));
9063 mMuteAwaitConnectionListeners = res.first;
9064 mMuteAwaitConnDispatcherStub = res.second;
9065 }
9066 }
9067
9068 /**
9069 * @hide
9070 * Unregister a previously registered callback for playback muting conditional on device
9071 * connection.
9072 * @param callback the callback to unregister
9073 */
9074 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009075 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009076 public void unregisterMuteAwaitConnectionCallback(
9077 @NonNull MuteAwaitConnectionCallback callback) {
9078 synchronized (mMuteAwaitConnectionListenerLock) {
9079 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9080 MuteAwaitConnectionDispatcherStub> res =
9081 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
9082 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
9083 stub -> stub.register(false));
9084 mMuteAwaitConnectionListeners = res.first;
9085 mMuteAwaitConnDispatcherStub = res.second;
9086 }
9087 }
9088
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009089 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009090 * Add UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009091 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009092 * @param assistantUids UIDs of the services that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009093 *
9094 * @hide
9095 */
9096 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009097 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009098 public void addAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009099 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009100 getService().addAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009101 } catch (RemoteException e) {
9102 throw e.rethrowFromSystemServer();
9103 }
9104 }
9105
9106 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009107 * Remove UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009108 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009109 * @param assistantUids UIDs of the services that should be remove.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009110 *
9111 * @hide
9112 */
9113 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009114 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009115 public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009116 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009117 getService().removeAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009118 } catch (RemoteException e) {
9119 throw e.rethrowFromSystemServer();
9120 }
9121 }
9122
9123 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009124 * Get the assistants UIDs that been added with the
9125 * {@link #addAssistantServicesUids(int[])} and not yet removed with
9126 * {@link #removeAssistantServicesUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009127 *
Oscar Azucena3ae33762022-03-04 04:44:59 +00009128 * <p> Note that during native audioserver crash and after boot up the list of assistant
9129 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
9130 * Just after user switch, the list of assistant will also reset to empty.
9131 * In both cases,The component's UID of the assistiant role or assistant setting will be
9132 * automitically added to the list by the audio service.
9133 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009134 * @return array of assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009135 *
9136 * @hide
9137 */
9138 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009139 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009140 public @NonNull int[] getAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009141 try {
9142 int[] uids = getService().getAssistantServicesUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00009143 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009144 } catch (RemoteException e) {
9145 throw e.rethrowFromSystemServer();
9146 }
9147 }
9148
9149 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009150 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
9151 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
9152 * In this manner calling the API with an empty array will remove all UIDs previously set.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009153 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009154 * @param assistantUids UIDs of the services that can be considered active assistant. Can be
9155 * an empty array, for this no UID will be considered active.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009156 *
9157 * <p> Note that during audio service crash reset and after boot up the list of active assistant
Oscar Azucena88467fe2022-02-15 21:55:11 +00009158 * 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 -08009159 * Just after user switch the list of active assistant will also reset to empty.
9160 *
9161 * @hide
9162 */
9163 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009164 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009165 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009166 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009167 getService().setActiveAssistantServiceUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009168 } catch (RemoteException e) {
9169 throw e.rethrowFromSystemServer();
9170 }
9171 }
9172
9173 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009174 * Get active assistant UIDs last set with the
9175 * {@link #setActiveAssistantServiceUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009176 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009177 * @return array of active assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009178 *
9179 * @hide
9180 */
9181 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009182 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009183 public @NonNull int[] getActiveAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009184 try {
9185 int[] uids = getService().getActiveAssistantServiceUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00009186 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009187 } catch (RemoteException e) {
9188 throw e.rethrowFromSystemServer();
9189 }
9190 }
9191
jiabinfe6b7f12022-02-04 18:45:44 +00009192 /**
Shunkai Yao601b6132022-11-22 01:47:48 +00009193 * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio
9194 * HAL found, null will be returned.
jiabinfe6b7f12022-02-04 18:45:44 +00009195 *
Shunkai Yao601b6132022-11-22 01:47:48 +00009196 * @return @see @link #AudioHalVersionInfo The version of Audio HAL.
jiabinfe6b7f12022-02-04 18:45:44 +00009197 * @hide
9198 */
9199 @TestApi
Shunkai Yao601b6132022-11-22 01:47:48 +00009200 public static @Nullable AudioHalVersionInfo getHalVersion() {
jiabinfe6b7f12022-02-04 18:45:44 +00009201 try {
9202 return getService().getHalVersion();
9203 } catch (RemoteException e) {
9204 Log.e(TAG, "Error querying getHalVersion", e);
9205 throw e.rethrowFromSystemServer();
9206 }
9207 }
9208
jiabin89f87ed2022-12-01 22:55:05 +00009209 //====================================================================
9210 // Preferred mixer attributes
9211
9212 /**
9213 * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixe
9214 * attributes via {@link #setPreferredMixerAttributes(
9215 * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}.
9216 * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes, the
9217 * returned list may be empty when devices do not allow dynamic configuration.
9218 *
9219 * @param device the device to query
9220 * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes
9221 * for the given device.
9222 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9223 */
9224 @NonNull
9225 public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) {
9226 Objects.requireNonNull(device);
9227 List<AudioMixerAttributes> mixerAttrs = new ArrayList<>();
9228 return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs)
9229 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>();
9230 }
9231
9232 /**
9233 * Configures the mixer attributes for a particular {@link AudioAttributes} over a given
9234 * {@link AudioDeviceInfo}.
9235 * <p>When constructing an {@link AudioMixerAttributes} for setting preferred mixer attributes,
9236 * the mixer format must be constructed from an {@link AudioProfile} that can be used to set
9237 * preferred mixer attributes.
9238 * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the
9239 * same uid is routed to the given audio device when calling this API, the output mixer/stream
9240 * will be configured with the values previously set via this API.
9241 * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)}
9242 * to cancel setting mixer attributes for this {@link AudioAttributes}.
9243 *
9244 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9245 * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When
9246 * playing audio targeted at the given device, use the same attributes for
9247 * playback.
9248 * @param device the device to be routed. Currently, only USB device will be allowed.
9249 * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the
9250 * given device, use the same {@link AudioFormat} for both playback
9251 * and the mixer attributes.
9252 * @return true only if the preferred mixer attributes are set successfully.
9253 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9254 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9255 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009256 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
jiabin89f87ed2022-12-01 22:55:05 +00009257 public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
9258 @NonNull AudioDeviceInfo device,
9259 @NonNull AudioMixerAttributes mixerAttributes) {
9260 Objects.requireNonNull(attributes);
9261 Objects.requireNonNull(device);
9262 Objects.requireNonNull(mixerAttributes);
9263 try {
9264 final int status = getService().setPreferredMixerAttributes(
9265 attributes, device.getId(), mixerAttributes);
9266 return status == AudioSystem.SUCCESS;
9267 } catch (RemoteException e) {
9268 throw e.rethrowFromSystemServer();
9269 }
9270 }
9271
9272 /**
9273 * Returns current preferred mixer attributes that is set via
9274 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9275 *
9276 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9277 * @param device the expected routing device
9278 * @return the preferred mixer attributes, which will be null when no preferred mixer attributes
9279 * have been set, or when they have been cleared.
9280 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9281 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9282 */
9283 @Nullable
9284 public AudioMixerAttributes getPreferredMixerAttributes(
9285 @NonNull AudioAttributes attributes,
9286 @NonNull AudioDeviceInfo device) {
9287 Objects.requireNonNull(attributes);
9288 Objects.requireNonNull(device);
9289 List<AudioMixerAttributes> mixerAttrList = new ArrayList<>();
9290 int ret = AudioSystem.getPreferredMixerAttributes(
9291 attributes, device.getId(), mixerAttrList);
9292 if (ret == AudioSystem.SUCCESS) {
9293 return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0);
9294 } else {
9295 Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret);
9296 return null;
9297 }
9298 }
9299
9300 /**
9301 * Clears the current preferred mixer attributes that were previously set via
9302 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9303 *
9304 * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared.
9305 * @param device the expected routing device
9306 * @return true only if the preferred mixer attributes are removed successfully.
9307 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9308 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9309 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009310 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
jiabin89f87ed2022-12-01 22:55:05 +00009311 public boolean clearPreferredMixerAttributes(
9312 @NonNull AudioAttributes attributes,
9313 @NonNull AudioDeviceInfo device) {
9314 Objects.requireNonNull(attributes);
9315 Objects.requireNonNull(device);
9316 try {
9317 final int status = getService().clearPreferredMixerAttributes(
9318 attributes, device.getId());
9319 return status == AudioSystem.SUCCESS;
9320 } catch (RemoteException e) {
9321 throw e.rethrowFromSystemServer();
9322 }
9323 }
9324
9325 /**
9326 * Interface to be notified of changes in the preferred mixer attributes.
9327 * <p>Note that this listener will only be invoked whenever
9328 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9329 * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device
9330 * disconnection causes a change in preferred mixer attributes.
9331 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9332 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9333 */
9334 public interface OnPreferredMixerAttributesChangedListener {
9335 /**
9336 * Called on the listener to indicate that the preferred mixer attributes for the audio
9337 * attributes over the given device has changed.
9338 *
9339 * @param attributes the audio attributes for playback
9340 * @param device the targeted device
9341 * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for
9342 * preferred mixer attributes or null if preferred mixer attributes
9343 * is cleared
9344 */
9345 void onPreferredMixerAttributesChanged(
9346 @NonNull AudioAttributes attributes,
9347 @NonNull AudioDeviceInfo device,
9348 @Nullable AudioMixerAttributes mixerAttributes);
9349 }
9350
9351 /**
9352 * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the
9353 * {@link PreferredMixerAttributesDispatcherStub}.
9354 */
9355 private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener>
9356 mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager();
9357
9358 /**
9359 * Adds a listener for being notified of changes to the preferred mixer attributes.
9360 * @param executor the executor to execute the callback
9361 * @param listener the listener to be notified of changes in the preferred mixer attributes.
9362 */
9363 public void addOnPreferredMixerAttributesChangedListener(
9364 @NonNull @CallbackExecutor Executor executor,
9365 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9366 Objects.requireNonNull(executor);
9367 Objects.requireNonNull(listener);
9368 mPrefMixerAttributesListenerMgr.addListener(executor, listener,
9369 "addOnPreferredMixerAttributesChangedListener",
9370 () -> new PreferredMixerAttributesDispatcherStub());
9371 }
9372
9373 /**
9374 * Removes a previously added listener of changes to the preferred mixer attributes.
9375 * @param listener the listener to be notified of changes in the preferred mixer attributes,
9376 * which were added via {@link #addOnPreferredMixerAttributesChangedListener(
9377 * Executor, OnPreferredMixerAttributesChangedListener)}.
9378 */
9379 public void removeOnPreferredMixerAttributesChangedListener(
9380 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9381 Objects.requireNonNull(listener);
9382 mPrefMixerAttributesListenerMgr.removeListener(listener,
9383 "removeOnPreferredMixerAttributesChangedListener");
9384 }
9385
9386 private final class PreferredMixerAttributesDispatcherStub
9387 extends IPreferredMixerAttributesDispatcher.Stub
9388 implements CallbackUtil.DispatcherStub {
9389
9390 @Override
9391 public void register(boolean register) {
9392 try {
9393 if (register) {
9394 getService().registerPreferredMixerAttributesDispatcher(this);
9395 } else {
9396 getService().unregisterPreferredMixerAttributesDispatcher(this);
9397 }
9398 } catch (RemoteException e) {
9399 e.rethrowFromSystemServer();
9400 }
9401 }
9402
9403 @Override
9404 public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr,
9405 int deviceId,
9406 @Nullable AudioMixerAttributes mixerAttr) {
9407 // TODO: If the device is disconnected, we may not be able to find the device with
9408 // given device id. We need a better to carry the device information via binder.
9409 AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS);
9410 if (device == null) {
9411 Log.d(TAG, "Drop preferred mixer attributes changed as the device("
9412 + deviceId + ") is disconnected");
9413 return;
9414 }
9415 mPrefMixerAttributesListenerMgr.callListeners(
9416 (listener) -> listener.onPreferredMixerAttributesChanged(
9417 attr, device, mixerAttr));
9418 }
9419 }
9420
Eric Laurent3c474bc2022-12-16 17:24:32 +01009421 /**
9422 * Requests if the implementation supports controlling the latency modes
9423 * over the Bluetooth A2DP or LE Audio links.
9424 *
9425 * @return true if supported, false otherwise
9426 *
9427 * @hide
9428 */
9429 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009430 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +01009431 public boolean supportsBluetoothVariableLatency() {
9432 try {
9433 return getService().supportsBluetoothVariableLatency();
9434 } catch (RemoteException e) {
9435 throw e.rethrowFromSystemServer();
9436 }
9437 }
9438
9439 /**
9440 * Enables or disables the variable Bluetooth latency control mechanism in the
9441 * audio framework and the audio HAL. This does not apply to the latency mode control
9442 * on the spatializer output as this is a built-in feature.
9443 *
9444 * @hide
9445 */
9446 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009447 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +01009448 public void setBluetoothVariableLatencyEnabled(boolean enabled) {
9449 try {
9450 getService().setBluetoothVariableLatencyEnabled(enabled);
9451 } catch (RemoteException e) {
9452 throw e.rethrowFromSystemServer();
9453 }
9454 }
9455
9456 /**
9457 * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
9458 * @hide
9459 */
9460 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009461 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +01009462 public boolean isBluetoothVariableLatencyEnabled() {
9463 try {
9464 return getService().isBluetoothVariableLatencyEnabled();
9465 } catch (RemoteException e) {
9466 throw e.rethrowFromSystemServer();
9467 }
9468 }
9469
jiabin89f87ed2022-12-01 22:55:05 +00009470 //====================================================================
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009471 // Stream aliasing changed listener, getter for stream alias or independent streams
9472
9473 /**
9474 * manages the stream aliasing listeners and StreamAliasingDispatcherStub
9475 */
9476 private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr =
9477 new CallbackUtil.LazyListenerManager();
9478
9479
9480 final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub
9481 implements CallbackUtil.DispatcherStub {
9482
9483 @Override
9484 public void register(boolean register) {
9485 try {
9486 getService().registerStreamAliasingDispatcher(this, register);
9487 } catch (RemoteException e) {
9488 e.rethrowFromSystemServer();
9489 }
9490 }
9491
9492 @Override
9493 public void dispatchStreamAliasingChanged() {
9494 mStreamAliasingListenerMgr.callListeners((listener) -> listener.run());
9495 }
9496 }
9497
9498 /**
9499 * @hide
9500 * Adds a listener to be notified of changes to volume stream type aliasing.
9501 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
9502 * @param executor the Executor running the listener
9503 * @param onStreamAliasingChangedListener the listener to add for the aliasing changes
9504 */
9505 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009506 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009507 public void addOnStreamAliasingChangedListener(
9508 @NonNull @CallbackExecutor Executor executor,
9509 @NonNull Runnable onStreamAliasingChangedListener) {
9510 mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener,
9511 "addOnStreamAliasingChangedListener",
9512 () -> new StreamAliasingDispatcherStub());
9513 }
9514
9515 /**
9516 * @hide
9517 * Removes a previously added listener for changes to stream aliasing.
9518 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
9519 * @see #addOnStreamAliasingChangedListener(Executor, Runnable)
9520 * @param onStreamAliasingChangedListener the previously added listener of aliasing changes
9521 */
9522 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009523 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009524 public void removeOnStreamAliasingChangedListener(
9525 @NonNull Runnable onStreamAliasingChangedListener) {
9526 mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener,
9527 "removeOnStreamAliasingChangedListener");
9528 }
9529
9530 /**
9531 * @hide
9532 * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING,
9533 * volumes will be updated in case of a change.
9534 * @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING
9535 */
9536 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009537 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009538 public void setNotifAliasRingForTest(boolean isAliased) {
9539 final IAudioService service = getService();
9540 try {
9541 service.setNotifAliasRingForTest(isAliased);
9542 } catch (RemoteException e) {
9543 throw e.rethrowFromSystemServer();
9544 }
9545 }
9546
9547 /**
9548 * @hide
9549 * Return the list of independent stream types for volume control.
9550 * A stream type is considered independent when the volume changes of that type do not
9551 * affect any other independent volume control stream type.
9552 * An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}.
9553 * @return list of independent stream types.
9554 */
9555 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009556 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009557 public @NonNull List<Integer> getIndependentStreamTypes() {
9558 final IAudioService service = getService();
9559 try {
9560 return service.getIndependentStreamTypes();
9561 } catch (RemoteException e) {
9562 throw e.rethrowFromSystemServer();
9563 }
9564 }
9565
9566 /**
9567 * @hide
9568 * Return the stream type that a given stream is aliased to.
9569 * A stream alias means that any change to the source stream will also be applied to the alias,
9570 * and vice-versa.
9571 * If a stream is independent (i.e. part of the stream types returned by
9572 * {@link #getIndependentStreamTypes()}), its alias is itself.
9573 * @param sourceStreamType the stream type to query for the alias.
9574 * @return the stream type the source type is aliased to.
9575 */
9576 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009577 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009578 public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) {
9579 final IAudioService service = getService();
9580 try {
9581 return service.getStreamTypeAlias(sourceStreamType);
9582 } catch (RemoteException e) {
9583 throw e.rethrowFromSystemServer();
9584 }
9585 }
9586
9587 /**
9588 * @hide
9589 * Returns whether the system uses {@link AudioVolumeGroup} for volume control
9590 * @return true when volume control is performed through volume groups, false if it uses
9591 * stream types.
9592 */
9593 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009594 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009595 public boolean isVolumeControlUsingVolumeGroups() {
9596 final IAudioService service = getService();
9597 try {
9598 return service.isVolumeControlUsingVolumeGroups();
9599 } catch (RemoteException e) {
9600 throw e.rethrowFromSystemServer();
9601 }
9602 }
9603
9604 //====================================================================
jiabin89f87ed2022-12-01 22:55:05 +00009605 // Mute await connection
9606
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009607 private final Object mMuteAwaitConnectionListenerLock = new Object();
9608
9609 @GuardedBy("mMuteAwaitConnectionListenerLock")
9610 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
9611 mMuteAwaitConnectionListeners;
9612
9613 @GuardedBy("mMuteAwaitConnectionListenerLock")
9614 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
9615
9616 private final class MuteAwaitConnectionDispatcherStub
9617 extends IMuteAwaitConnectionCallback.Stub {
9618 public void register(boolean register) {
9619 try {
9620 getService().registerMuteAwaitConnectionDispatcher(this, register);
9621 } catch (RemoteException e) {
9622 throw e.rethrowFromSystemServer();
9623 }
9624 }
9625
9626 @Override
9627 @SuppressLint("GuardedBy") // lock applied inside callListeners method
9628 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
9629 int[] mutedUsages) {
9630 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
9631 mMuteAwaitConnectionListenerLock,
9632 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
9633 }
9634
9635 @Override
9636 @SuppressLint("GuardedBy") // lock applied inside callListeners method
9637 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
9638 int[] mutedUsages) {
9639 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
9640 mMuteAwaitConnectionListenerLock,
9641 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
9642 }
9643 }
9644
9645 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07009646 // Inner classes
9647 //--------------------
9648 /**
9649 * Helper class to handle the forwarding of native events to the appropriate listener
9650 * (potentially) handled in a different thread.
9651 */
9652 private class NativeEventHandlerDelegate {
9653 private final Handler mHandler;
9654
Paul McLean03346882015-05-12 15:36:56 -07009655 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07009656 Handler handler) {
9657 // find the looper for our new event handler
9658 Looper looper;
9659 if (handler != null) {
9660 looper = handler.getLooper();
9661 } else {
9662 // no given handler, use the looper the addListener call was called in
9663 looper = Looper.getMainLooper();
9664 }
9665
9666 // construct the event handler with this looper
9667 if (looper != null) {
9668 // implement the event handler delegate
9669 mHandler = new Handler(looper) {
9670 @Override
9671 public void handleMessage(Message msg) {
9672 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07009673 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07009674 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07009675 if (callback != null) {
9676 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07009677 }
9678 break;
Paul McLean03346882015-05-12 15:36:56 -07009679
9680 case MSG_DEVICES_DEVICES_REMOVED:
9681 if (callback != null) {
9682 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
9683 }
9684 break;
9685
Paul McLeane3383cc2015-05-08 11:41:20 -07009686 default:
9687 Log.e(TAG, "Unknown native event type: " + msg.what);
9688 break;
9689 }
9690 }
9691 };
9692 } else {
9693 mHandler = null;
9694 }
9695 }
9696
9697 Handler getHandler() {
9698 return mHandler;
9699 }
9700 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08009701}