blob: 5bc634976a0ca6f01df16e52a02f85e8d59fb89a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010019import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
20import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
Marco Loaiza7b7d2af2023-01-23 15:21:52 +000021import static android.content.Context.DEVICE_ID_DEFAULT;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +010022
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
Jean-Michel Trivi23123b62023-02-14 01:22:31 +0000684 /** @hide */
685 @IntDef(flag = true, prefix = "FLAG", value = {
686 FLAG_SHOW_UI,
687 FLAG_ALLOW_RINGER_MODES,
688 FLAG_PLAY_SOUND,
689 FLAG_REMOVE_SOUND_AND_VIBRATE,
690 FLAG_VIBRATE,
691 FLAG_BLUETOOTH_ABS_VOLUME,
692 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
693 FLAG_FROM_KEY,
694 })
695 @Retention(RetentionPolicy.SOURCE)
696 public @interface SystemVolumeFlags {}
697
Hyundo Moonca0080d2018-12-26 16:16:55 +0900698 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
699 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
700
701 static {
702 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
703 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
704 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
705 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
706 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
707 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
708 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
709 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
710 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
711 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
712 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
713 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
714 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
Yan Han7d419822022-01-31 19:10:16 +0100715 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
Hyundo Moonca0080d2018-12-26 16:16:55 +0900716 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500717
718 /** @hide */
719 public static String flagsToString(int flags) {
720 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900721 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
722 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500723 if ((flags & flag) != 0) {
724 if (sb.length() > 0) {
725 sb.append(',');
726 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900727 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500728 flags &= ~flag;
729 }
730 }
731 if (flags != 0) {
732 if (sb.length() > 0) {
733 sb.append(',');
734 }
735 sb.append(flags);
736 }
737 return sb.toString();
738 }
739
740 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 * Ringer mode that will be silent and will not vibrate. (This overrides the
742 * vibrate setting.)
743 *
744 * @see #setRingerMode(int)
745 * @see #getRingerMode()
746 */
747 public static final int RINGER_MODE_SILENT = 0;
748
749 /**
750 * Ringer mode that will be silent and will vibrate. (This will cause the
751 * phone ringer to always vibrate, but the notification vibrate to only
752 * vibrate if set.)
753 *
754 * @see #setRingerMode(int)
755 * @see #getRingerMode()
756 */
757 public static final int RINGER_MODE_VIBRATE = 1;
758
759 /**
760 * Ringer mode that may be audible and may vibrate. It will be audible if
761 * the volume before changing out of this mode was audible. It will vibrate
762 * if the vibrate setting is on.
763 *
764 * @see #setRingerMode(int)
765 * @see #getRingerMode()
766 */
767 public static final int RINGER_MODE_NORMAL = 2;
768
John Spurlock97559372014-10-24 16:27:36 -0400769 /**
770 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
771 * @hide
772 */
773 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 /**
776 * Vibrate type that corresponds to the ringer.
777 *
778 * @see #setVibrateSetting(int, int)
779 * @see #getVibrateSetting(int)
780 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700781 * @deprecated Applications should maintain their own vibrate policy based on
782 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 */
784 public static final int VIBRATE_TYPE_RINGER = 0;
785
786 /**
787 * Vibrate type that corresponds to notifications.
788 *
789 * @see #setVibrateSetting(int, int)
790 * @see #getVibrateSetting(int)
791 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700792 * @deprecated Applications should maintain their own vibrate policy based on
793 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 */
795 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
796
797 /**
798 * Vibrate setting that suggests to never vibrate.
799 *
800 * @see #setVibrateSetting(int, int)
801 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700802 * @deprecated Applications should maintain their own vibrate policy based on
803 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 */
805 public static final int VIBRATE_SETTING_OFF = 0;
806
807 /**
808 * Vibrate setting that suggests to vibrate when possible.
809 *
810 * @see #setVibrateSetting(int, int)
811 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700812 * @deprecated Applications should maintain their own vibrate policy based on
813 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 */
815 public static final int VIBRATE_SETTING_ON = 1;
816
817 /**
818 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
819 * mode.
820 *
821 * @see #setVibrateSetting(int, int)
822 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700823 * @deprecated Applications should maintain their own vibrate policy based on
824 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 */
826 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
827
828 /**
829 * Suggests using the default stream type. This may not be used in all
830 * places a stream type is needed.
831 */
832 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
833
834 private static IAudioService sService;
835
836 /**
837 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800838 * For test purposes only, will throw NPE with some methods that require a Context.
839 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000840 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800841 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800842 }
843
844 /**
845 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100847 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700849 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 }
851
Marco Nelissen29f16932015-04-17 09:50:56 -0700852 private Context getContext() {
853 if (mApplicationContext == null) {
854 setContext(mOriginalContext);
855 }
856 if (mApplicationContext != null) {
857 return mApplicationContext;
858 }
859 return mOriginalContext;
860 }
861
862 private void setContext(Context context) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +0000863 mOriginalContextDeviceId = context.getDeviceId();
Marco Nelissen29f16932015-04-17 09:50:56 -0700864 mApplicationContext = context.getApplicationContext();
865 if (mApplicationContext != null) {
866 mOriginalContext = null;
867 } else {
868 mOriginalContext = context;
869 }
jiabin0f3339c2021-07-09 11:50:07 -0700870 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700871 }
872
Mathew Inwood31a792a2018-08-17 08:54:26 +0100873 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700874 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 {
876 if (sService != null) {
877 return sService;
878 }
879 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
880 sService = IAudioService.Stub.asInterface(b);
881 return sService;
882 }
883
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +0100884 private VirtualDeviceManager getVirtualDeviceManager() {
885 if (mVirtualDeviceManager != null) {
886 return mVirtualDeviceManager;
887 }
888 mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class);
889 return mVirtualDeviceManager;
890 }
891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700893 * Sends a simulated key event for a media button.
894 * To simulate a key press, you must first send a KeyEvent built with a
895 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
896 * action.
897 * <p>The key event will be sent to the current media key event consumer which registered with
898 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
899 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
900 * {@link KeyEvent#KEYCODE_MUTE},
901 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
902 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
903 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
904 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
905 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
906 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
907 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
908 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
909 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
910 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
911 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
912 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
913 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700914 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700915 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700916 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700917 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700918 }
919
920 /**
921 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700922 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800923 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700924 /*
925 * If the user hits another key within the play sound delay, then
926 * cancel the sound
927 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800928 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700929 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
930 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
Santiago Seifert75969912023-01-18 11:11:30 +0000931 && AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700932 /*
933 * The user has hit another key during the delay (e.g., 300ms)
934 * since the last volume key up, so cancel any sounds.
935 */
John Spurlockee5ad722015-03-03 16:17:21 -0500936 adjustSuggestedStreamVolume(ADJUST_SAME,
937 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700938 }
939 }
940
941 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700942 * Indicates if the device implements a fixed volume policy.
943 * <p>Some devices may not have volume control and may operate at a fixed volume,
944 * and may not enable muting or changing the volume of audio streams.
945 * This method will return true on such devices.
946 * <p>The following APIs have no effect when volume is fixed:
947 * <ul>
948 * <li> {@link #adjustVolume(int, int)}
949 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
950 * <li> {@link #adjustStreamVolume(int, int, int)}
951 * <li> {@link #setStreamVolume(int, int, int)}
952 * <li> {@link #setRingerMode(int)}
953 * <li> {@link #setStreamSolo(int, boolean)}
954 * <li> {@link #setStreamMute(int, boolean)}
955 * </ul>
956 */
957 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700958 boolean res = false;
959 try {
960 res = getService().isVolumeFixed();
961 } catch (RemoteException e) {
962 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700963 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700964 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700965 }
966
967 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700969 * <p>
970 * This method should only be used by applications that replace the platform-wide
971 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700972 * <p>This method has no effect if the device implements a fixed volume policy
973 * as indicated by {@link #isVolumeFixed()}.
974 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
975 * unless the app has been granted Do Not Disturb Access.
976 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 *
978 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800979 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
980 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 * @param direction The direction to adjust the volume. One of
982 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
983 * {@link #ADJUST_SAME}.
984 * @param flags One or more flags.
985 * @see #adjustVolume(int, int)
986 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700987 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
988 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 */
990 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700991 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 try {
John Wu4f7e5102021-06-22 17:29:11 +0000993 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
994 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700996 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
998 }
999
1000 /**
1001 * Adjusts the volume of the most relevant stream. For example, if a call is
1002 * active, it will have the highest priority regardless of if the in-call
1003 * screen is showing. Another example, if music is playing in the background
1004 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001005 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001006 * This method should only be used by applications that replace the
1007 * platform-wide management of audio settings or the main telephony
1008 * application.
1009 * <p>
1010 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001011 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001012 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001014 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1015 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1016 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 * @param flags One or more flags.
1018 * @see #adjustSuggestedStreamVolume(int, int, int)
1019 * @see #adjustStreamVolume(int, int, int)
1020 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001021 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 */
1023 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001024 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001025 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027
1028 /**
1029 * Adjusts the volume of the most relevant stream, or the given fallback
1030 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001031 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001032 * This method should only be used by applications that replace the
1033 * platform-wide management of audio settings or the main telephony
1034 * application.
1035 * <p>
1036 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001037 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001038 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001040 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1041 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1042 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001044 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1045 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 * @param flags One or more flags.
1047 * @see #adjustVolume(int, int)
1048 * @see #adjustStreamVolume(int, int, int)
1049 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001050 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 */
1052 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001053 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001054 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001055 }
1056
John Spurlockee5ad722015-03-03 16:17:21 -05001057 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001058 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001059 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001060 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001061 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001062 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001063 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001064 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001065 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001066 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068 }
1069
1070 /**
1071 * Returns the current ringtone mode.
1072 *
1073 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1074 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1075 * @see #setRingerMode(int)
1076 */
1077 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001078 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001080 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001082 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084 }
1085
1086 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001087 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1088 *
1089 * @return true if the incoming phone call ringtone is configured to gradually increase its
1090 * volume, false otherwise.
1091 */
1092 public boolean isRampingRingerEnabled() {
1093 return Settings.System.getInt(getContext().getContentResolver(),
1094 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1095 }
1096
1097 /**
1098 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1099 *
1100 * @see #isRampingRingerEnabled()
1101 * @hide
1102 */
1103 @TestApi
1104 public void setRampingRingerEnabled(boolean enabled) {
1105 Settings.System.putInt(getContext().getContentResolver(),
1106 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1107 }
1108
1109 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001110 * Checks valid ringer mode values.
1111 *
1112 * @return true if the ringer mode indicated is valid, false otherwise.
1113 *
1114 * @see #setRingerMode(int)
1115 * @hide
1116 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001117 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001118 public static boolean isValidRingerMode(int ringerMode) {
1119 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1120 return false;
1121 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001122 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001123 try {
1124 return service.isValidRingerMode(ringerMode);
1125 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001126 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001127 }
Eric Laurent72668b22011-07-19 16:04:27 -07001128 }
1129
1130 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 * Returns the maximum volume index for a particular stream.
1132 *
1133 * @param streamType The stream type whose maximum volume index is returned.
1134 * @return The maximum valid volume index for the stream.
1135 * @see #getStreamVolume(int)
1136 */
1137 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001138 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001140 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001142 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 }
1144 }
1145
1146 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001147 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001148 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1149 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1150 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1151 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1152 * @return The minimum valid volume index for the stream.
1153 * @see #getStreamVolume(int)
1154 */
1155 public int getStreamMinVolume(int streamType) {
1156 if (!isPublicStreamType(streamType)) {
1157 throw new IllegalArgumentException("Invalid stream type " + streamType);
1158 }
1159 return getStreamMinVolumeInt(streamType);
1160 }
1161
1162 /**
1163 * @hide
1164 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001165 * @param streamType The stream type whose minimum volume index is returned.
1166 * @return The minimum valid volume index for the stream.
1167 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001168 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001169 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001170 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001171 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001172 try {
1173 return service.getStreamMinVolume(streamType);
1174 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001175 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001176 }
1177 }
1178
1179 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 * Returns the current volume index for a particular stream.
1181 *
1182 * @param streamType The stream type whose volume index is returned.
1183 * @return The current volume index for the stream.
1184 * @see #getStreamMaxVolume(int)
1185 * @see #setStreamVolume(int, int, int)
1186 */
1187 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001188 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001190 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001192 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194 }
1195
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001196 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1197 private static final float VOLUME_MIN_DB = -758.0f;
1198
1199 /** @hide */
1200 @IntDef(flag = false, prefix = "STREAM", value = {
1201 STREAM_VOICE_CALL,
1202 STREAM_SYSTEM,
1203 STREAM_RING,
1204 STREAM_MUSIC,
1205 STREAM_ALARM,
1206 STREAM_NOTIFICATION,
1207 STREAM_DTMF,
1208 STREAM_ACCESSIBILITY }
1209 )
1210 @Retention(RetentionPolicy.SOURCE)
1211 public @interface PublicStreamTypes {}
1212
1213 /**
1214 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1215 * the given type of audio output device.
1216 * @param streamType stream type for which the volume is queried.
1217 * @param index the volume index for which the volume is queried. The index value must be
1218 * between the minimum and maximum index values for the given stream type (see
1219 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1220 * @param deviceType the type of audio output device for which volume is queried.
1221 * @return a volume expressed in dB.
1222 * A negative value indicates the audio signal is attenuated. A typical maximum value
1223 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1224 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1225 */
1226 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1227 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1228 if (!isPublicStreamType(streamType)) {
1229 throw new IllegalArgumentException("Invalid stream type " + streamType);
1230 }
1231 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1232 throw new IllegalArgumentException("Invalid stream volume index " + index);
1233 }
1234 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1235 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1236 }
1237 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1238 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1239 if (gain <= VOLUME_MIN_DB) {
1240 return Float.NEGATIVE_INFINITY;
1241 } else {
1242 return gain;
1243 }
1244 }
1245
Jean-Michel Trivi283a4c72022-09-28 21:46:51 +00001246 /**
1247 * @hide
1248 * Checks whether a stream type is part of the public SDK
1249 * @param streamType
1250 * @return true if the stream type is available in SDK
1251 */
1252 public static boolean isPublicStreamType(int streamType) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001253 switch (streamType) {
1254 case STREAM_VOICE_CALL:
1255 case STREAM_SYSTEM:
1256 case STREAM_RING:
1257 case STREAM_MUSIC:
1258 case STREAM_ALARM:
1259 case STREAM_NOTIFICATION:
1260 case STREAM_DTMF:
1261 case STREAM_ACCESSIBILITY:
1262 return true;
1263 default:
1264 return false;
1265 }
1266 }
1267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001269 * Get last audible volume before stream was muted.
1270 *
1271 * @hide
1272 */
wescandee178f8f2021-10-19 20:15:09 +02001273 @SystemApi
1274 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001275 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001276 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001277 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001278 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001279 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001280 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001281 }
1282 }
1283
1284 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001285 * Get the stream type whose volume is driving the UI sounds volume.
1286 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001287 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001288 * @hide
1289 */
John Spurlockee5ad722015-03-03 16:17:21 -05001290 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001291 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001292 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001293 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001294 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001295 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001296 }
1297 }
1298
1299 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 * Sets the ringer mode.
1301 * <p>
1302 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1303 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1304 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001305 * <p>This method has no effect if the device implements a fixed volume policy
1306 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001307 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1308 * unless the app has been granted Do Not Disturb Access.
1309 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1311 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1312 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001313 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 */
1315 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001316 if (!isValidRingerMode(ringerMode)) {
1317 return;
1318 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001319 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001321 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001323 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 }
1325 }
1326
1327 /**
1328 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001329 * <p>This method has no effect if the device implements a fixed volume policy
1330 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001331 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1332 * the app has been granted Do Not Disturb Access.
1333 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 * @param streamType The stream whose volume index should be set.
1335 * @param index The volume index to set. See
1336 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1337 * @param flags One or more flags.
1338 * @see #getStreamMaxVolume(int)
1339 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001340 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001341 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1342 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 */
1344 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001345 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 try {
John Wu4f7e5102021-06-22 17:29:11 +00001347 service.setStreamVolumeWithAttribution(streamType, index, flags,
1348 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001350 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 }
1352 }
1353
1354 /**
François Gaffie9c362102018-09-21 17:43:52 +02001355 * Sets the volume index for a particular {@link AudioAttributes}.
1356 * @param attr The {@link AudioAttributes} whose volume index should be set.
1357 * @param index The volume index to set. See
1358 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1359 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1360 * @param flags One or more flags.
1361 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1362 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1363 * @see #isVolumeFixed()
1364 * @hide
1365 */
1366 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001367 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001368 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1369 Preconditions.checkNotNull(attr, "attr must not be null");
1370 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001371 int groupId = getVolumeGroupIdForAttributes(attr);
1372 setVolumeGroupVolumeIndex(groupId, index, flags);
François Gaffie9c362102018-09-21 17:43:52 +02001373 }
1374
1375 /**
1376 * Returns the current volume index for a particular {@link AudioAttributes}.
1377 *
1378 * @param attr The {@link AudioAttributes} whose volume index is returned.
1379 * @return The current volume index for the stream.
1380 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1381 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1382 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1383 * @hide
1384 */
1385 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001386 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001387 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001388 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1389 Preconditions.checkNotNull(attr, "attr must not be null");
1390 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001391 int groupId = getVolumeGroupIdForAttributes(attr);
1392 return getVolumeGroupVolumeIndex(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001393 }
1394
1395 /**
1396 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1397 *
1398 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1399 * @return The maximum valid volume index for the {@link AudioAttributes}.
1400 * @see #getVolumeIndexForAttributes(AudioAttributes)
1401 * @hide
1402 */
1403 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001404 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001405 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001406 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1407 Preconditions.checkNotNull(attr, "attr must not be null");
1408 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001409 int groupId = getVolumeGroupIdForAttributes(attr);
1410 return getVolumeGroupMaxVolumeIndex(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001411 }
1412
1413 /**
1414 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1415 *
1416 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1417 * @return The minimum valid volume index for the {@link AudioAttributes}.
1418 * @see #getVolumeIndexForAttributes(AudioAttributes)
1419 * @hide
1420 */
1421 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001422 @IntRange(from = 0)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001423 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
François Gaffie9c362102018-09-21 17:43:52 +02001424 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1425 Preconditions.checkNotNull(attr, "attr must not be null");
1426 final IAudioService service = getService();
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001427 int groupId = getVolumeGroupIdForAttributes(attr);
1428 return getVolumeGroupMinVolumeIndex(groupId);
1429 }
1430
1431 /**
1432 * Returns the volume group id associated to the given {@link AudioAttributes}.
1433 *
1434 * @param attributes The {@link AudioAttributes} to consider.
1435 * @return {@link android.media.audiopolicy.AudioVolumeGroup} id supporting the given
1436 * {@link AudioAttributes} if found,
1437 * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
1438 */
1439 public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
1440 Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
1441 return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes,
Eric Laurent00c916c2023-02-03 20:50:06 +01001442 /* fallbackOnDefault= */ true);
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001443 }
1444
1445 /**
1446 * Sets the volume index for a particular group associated to given id.
1447 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1448 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1449 *
1450 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1451 * @param index The volume index to set. See
1452 * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
1453 * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
1454 * @param flags One or more flags.
1455 * @hide
1456 */
1457 @SystemApi
1458 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001459 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001460 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1461 })
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001462 public void setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags) {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001463 final IAudioService service = getService();
François Gaffie9c362102018-09-21 17:43:52 +02001464 try {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001465 service.setVolumeGroupVolumeIndex(groupId, index, flags,
1466 getContext().getOpPackageName(), getContext().getAttributionTag());
1467 } catch (RemoteException e) {
1468 throw e.rethrowFromSystemServer();
1469 }
1470 }
1471
1472 /**
1473 * Returns the current volume index for a particular group associated to given id.
1474 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1475 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1476 *
1477 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1478 * @return The current volume index for the stream.
1479 * @hide
1480 */
1481 @SystemApi
1482 @IntRange(from = 0)
1483 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001484 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001485 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1486 })
1487 public int getVolumeGroupVolumeIndex(int groupId) {
1488 final IAudioService service = getService();
1489 try {
1490 return service.getVolumeGroupVolumeIndex(groupId);
1491 } catch (RemoteException e) {
1492 throw e.rethrowFromSystemServer();
1493 }
1494 }
1495
1496 /**
1497 * Returns the maximum volume index for a particular group associated to given id.
1498 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1499 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1500 *
1501 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1502 * @return The maximum valid volume index for the {@link AudioAttributes}.
1503 * @hide
1504 */
1505 @SystemApi
1506 @IntRange(from = 0)
1507 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001508 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001509 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1510 })
1511 public int getVolumeGroupMaxVolumeIndex(int groupId) {
1512 final IAudioService service = getService();
1513 try {
1514 return service.getVolumeGroupMaxVolumeIndex(groupId);
1515 } catch (RemoteException e) {
1516 throw e.rethrowFromSystemServer();
1517 }
1518 }
1519
1520 /**
1521 * Returns the minimum volume index for a particular group associated to given id.
1522 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1523 * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1524 *
1525 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1526 * @return The minimum valid volume index for the {@link AudioAttributes}.
1527 * @hide
1528 */
1529 @SystemApi
1530 @IntRange(from = 0)
1531 @RequiresPermission(anyOf = {
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00001532 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001533 android.Manifest.permission.MODIFY_AUDIO_ROUTING
1534 })
1535 public int getVolumeGroupMinVolumeIndex(int groupId) {
1536 final IAudioService service = getService();
1537 try {
1538 return service.getVolumeGroupMinVolumeIndex(groupId);
1539 } catch (RemoteException e) {
1540 throw e.rethrowFromSystemServer();
1541 }
1542 }
1543
1544 /**
1545 * Adjusts the volume of a particular group associated to given id by one step in a direction.
1546 * <p> If the volume group is associated to a stream type, it fallbacks on
1547 * {@link #adjustStreamVolume(int, int, int)} for compatibility reason.
1548 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1549 * the volume group id supporting the given {@link AudioAttributes}.
1550 *
1551 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1552 * @param direction The direction to adjust the volume. One of
1553 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
1554 * {@link #ADJUST_SAME}.
1555 * @param flags One or more flags.
1556 * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
1557 * is not granted notification policy access.
1558 */
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001559 public void adjustVolumeGroupVolume(int groupId, int direction, @SystemVolumeFlags int flags) {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001560 IAudioService service = getService();
1561 try {
1562 service.adjustVolumeGroupVolume(groupId, direction, flags,
1563 getContext().getOpPackageName());
1564 } catch (RemoteException e) {
1565 throw e.rethrowFromSystemServer();
1566 }
1567 }
1568
1569 /**
1570 * Get last audible volume of the group associated to given id before it was muted.
1571 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1572 * the volume group id supporting the given {@link AudioAttributes}.
1573 *
1574 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1575 * @return current volume if not muted, volume before muted otherwise.
1576 * @hide
1577 */
1578 @SystemApi
1579 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
1580 @IntRange(from = 0)
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001581 public int getLastAudibleVolumeForVolumeGroup(int groupId) {
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001582 IAudioService service = getService();
1583 try {
Jean-Michel Trivi23123b62023-02-14 01:22:31 +00001584 return service.getLastAudibleVolumeForVolumeGroup(groupId);
Francois Gaffie32a2b5f2021-11-10 13:45:42 +01001585 } catch (RemoteException e) {
1586 throw e.rethrowFromSystemServer();
1587 }
1588 }
1589
1590 /**
1591 * Returns the current mute state for a particular volume group associated to the given id.
1592 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1593 * the volume group id supporting the given {@link AudioAttributes}.
1594 *
1595 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1596 * @return The mute state for the given {@link android.media.audiopolicy.AudioVolumeGroup} id.
1597 * @see #adjustVolumeGroupVolume(int, int, int)
1598 */
1599 public boolean isVolumeGroupMuted(int groupId) {
1600 IAudioService service = getService();
1601 try {
1602 return service.isVolumeGroupMuted(groupId);
François Gaffie9c362102018-09-21 17:43:52 +02001603 } catch (RemoteException e) {
1604 throw e.rethrowFromSystemServer();
1605 }
1606 }
1607
1608 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001609 * Set the system usages to be supported on this device.
1610 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1611 * @hide
1612 */
1613 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001614 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes62812aa2019-12-23 11:40:27 -08001615 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1616 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1617 final IAudioService service = getService();
1618 try {
1619 service.setSupportedSystemUsages(systemUsages);
1620 } catch (RemoteException e) {
1621 throw e.rethrowFromSystemServer();
1622 }
1623 }
1624
1625 /**
1626 * Get the system usages supported on this device.
1627 * @return array of supported system usages {@link AttributeSystemUsage}
1628 * @hide
1629 */
1630 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001631 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes62812aa2019-12-23 11:40:27 -08001632 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1633 final IAudioService service = getService();
1634 try {
1635 return service.getSupportedSystemUsages();
1636 } catch (RemoteException e) {
1637 throw e.rethrowFromSystemServer();
1638 }
1639 }
1640
1641 /**
RoboErik4197cb62015-01-21 15:45:32 -08001642 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001644 * Do not use. This method has been deprecated and is now a no-op.
1645 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 *
1647 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001648 * @param state The required solo state: true for solo ON, false for solo
1649 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001650 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001651 * @deprecated Do not use. If you need exclusive audio playback use
1652 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 */
RoboErik4197cb62015-01-21 15:45:32 -08001654 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001656 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 }
1658
1659 /**
1660 * Mute or unmute an audio stream.
1661 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001662 * This method should only be used by applications that replace the
1663 * platform-wide management of audio settings or the main telephony
1664 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001666 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001667 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001668 * <p>
1669 * This method was deprecated in API level 22. Prior to API level 22 this
1670 * method had significantly different behavior and should be used carefully.
1671 * The following applies only to pre-22 platforms:
1672 * <ul>
1673 * <li>The mute command is protected against client process death: if a
1674 * process with an active mute request on a stream dies, this stream will be
1675 * unmuted automatically.</li>
1676 * <li>The mute requests for a given stream are cumulative: the AudioManager
1677 * can receive several mute requests from one or more clients and the stream
1678 * will be unmuted only when the same number of unmute requests are
1679 * received.</li>
1680 * <li>For a better user experience, applications MUST unmute a muted stream
1681 * in onPause() and mute is again in onResume() if appropriate.</li>
1682 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 *
1684 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001685 * @param state The required mute state: true for mute ON, false for mute
1686 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001687 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001688 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1689 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 */
RoboErik4197cb62015-01-21 15:45:32 -08001691 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001693 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1694 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1695 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1696 adjustSuggestedStreamVolume(direction, streamType, 0);
1697 } else {
1698 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
1700 }
1701
1702 /**
RoboErik4197cb62015-01-21 15:45:32 -08001703 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001704 *
RoboErik4197cb62015-01-21 15:45:32 -08001705 * @param streamType The stream to get mute state for.
1706 * @return The mute state for the given stream.
1707 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001708 */
1709 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001710 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001711 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001712 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001713 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001714 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001715 }
1716 }
1717
1718 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001719 * get master mute state.
1720 *
1721 * @hide
1722 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001723 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001724 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001725 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001726 try {
1727 return service.isMasterMute();
1728 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001729 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001730 }
1731 }
1732
1733 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001734 * forces the stream controlled by hard volume keys
1735 * specifying streamType == -1 releases control to the
1736 * logic.
1737 *
1738 * @hide
1739 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001740 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001741 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001742 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001743 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001744 try {
1745 service.forceVolumeControlStream(streamType, mICallBack);
1746 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001747 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001748 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001749 }
1750
1751 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 * Returns whether a particular type should vibrate according to user
1753 * settings and the current ringer mode.
1754 * <p>
1755 * This shouldn't be needed by most clients that use notifications to
1756 * vibrate. The notification manager will not vibrate if the policy doesn't
1757 * allow it, so the client should always set a vibrate pattern and let the
1758 * notification manager control whether or not to actually vibrate.
1759 *
1760 * @param vibrateType The type of vibrate. One of
1761 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1762 * {@link #VIBRATE_TYPE_RINGER}.
1763 * @return Whether the type should vibrate at the instant this method is
1764 * called.
1765 * @see #setVibrateSetting(int, int)
1766 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001767 * @deprecated Applications should maintain their own vibrate policy based on
1768 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 */
1770 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001771 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 try {
1773 return service.shouldVibrate(vibrateType);
1774 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001775 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 }
1777 }
1778
1779 /**
1780 * Returns whether the user's vibrate setting for a vibrate type.
1781 * <p>
1782 * This shouldn't be needed by most clients that want to vibrate, instead
1783 * see {@link #shouldVibrate(int)}.
1784 *
1785 * @param vibrateType The type of vibrate. One of
1786 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1787 * {@link #VIBRATE_TYPE_RINGER}.
1788 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1789 * {@link #VIBRATE_SETTING_OFF}, or
1790 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1791 * @see #setVibrateSetting(int, int)
1792 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001793 * @deprecated Applications should maintain their own vibrate policy based on
1794 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 */
1796 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001797 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 try {
1799 return service.getVibrateSetting(vibrateType);
1800 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001801 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 }
1803 }
1804
1805 /**
1806 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001807 * <p>
1808 * This method should only be used by applications that replace the platform-wide
1809 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810 *
1811 * @param vibrateType The type of vibrate. One of
1812 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1813 * {@link #VIBRATE_TYPE_RINGER}.
1814 * @param vibrateSetting The vibrate setting, one of
1815 * {@link #VIBRATE_SETTING_ON},
1816 * {@link #VIBRATE_SETTING_OFF}, or
1817 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1818 * @see #getVibrateSetting(int)
1819 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001820 * @deprecated Applications should maintain their own vibrate policy based on
1821 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 */
1823 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001824 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 try {
1826 service.setVibrateSetting(vibrateType, vibrateSetting);
1827 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001828 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 }
1830 }
1831
1832 /**
1833 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001834 * <p>
1835 * This method should only be used by applications that replace the platform-wide
1836 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 *
1838 * @param on set <var>true</var> to turn on speakerphone;
1839 * <var>false</var> to turn it off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001840 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or
1841 * {@link AudioManager#clearCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001843 @Deprecated public void setSpeakerphoneOn(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001844 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001845 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001846 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001847 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001848 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
1851
1852 /**
1853 * Checks whether the speakerphone is on or off.
1854 *
1855 * @return true if speakerphone is on, false if it's off
Eric Laurentf23f1b72022-02-18 10:57:54 +01001856 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01001858 @Deprecated public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001859 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001860 try {
1861 return service.isSpeakerphoneOn();
1862 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001863 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001867 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001868 * 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 -07001869 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001870 *
1871 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1872 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001873 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001874 * <ul>
1875 * <li> for each track independently, see
1876 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1877 * <li> application-wide at runtime, with this method </li>
1878 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1879 * manifest. </li>
1880 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001881 * The most restrictive policy is always applied.
1882 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001883 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001884 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001885 *
1886 * @param capturePolicy one of
1887 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1888 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1889 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001890 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001891 */
1892 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001893 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001894 final IAudioService service = getService();
1895 try {
1896 int result = service.setAllowedCapturePolicy(capturePolicy);
1897 if (result != AudioSystem.AUDIO_STATUS_OK) {
1898 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1899 return;
1900 }
1901 } catch (RemoteException e) {
1902 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001903 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001904 }
1905
Kevin Rocard019f60d2019-04-09 16:25:26 -07001906 /**
1907 * Return the capture policy.
1908 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1909 * the default if it was not called.
1910 */
1911 @AudioAttributes.CapturePolicy
1912 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001913 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1914 try {
1915 result = getService().getAllowedCapturePolicy();
1916 } catch (RemoteException e) {
1917 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1918 }
1919 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001920 }
1921
Eric Laurent3def1ee2010-03-17 23:26:26 -07001922 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001923 // Audio Product Strategy routing
1924
1925 /**
1926 * @hide
1927 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1928 * this audio strategy. Note that the device may not be available at the time the preferred
1929 * device is set, but it will be used once made available.
1930 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1931 * this preference for this strategy.</p>
1932 * @param strategy the audio strategy whose routing will be affected
1933 * @param device the audio device to route to when available
1934 * @return true if the operation was successful, false otherwise
1935 */
1936 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001937 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001938 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001939 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001940 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001941 }
1942
1943 /**
1944 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001945 * Removes the preferred audio device(s) previously set with
1946 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1947 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001948 * @param strategy the audio strategy whose routing will be affected
1949 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1950 * device set for example)
1951 */
1952 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001953 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001954 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1955 Objects.requireNonNull(strategy);
1956 try {
1957 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001958 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001959 return status == AudioSystem.SUCCESS;
1960 } catch (RemoteException e) {
1961 throw e.rethrowFromSystemServer();
1962 }
1963 }
1964
1965 /**
1966 * @hide
1967 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001968 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1969 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1970 * @param strategy the strategy to query
1971 * @return the preferred device for that strategy, if multiple devices are set as preferred
1972 * devices, the first one in the list will be returned. Null will be returned if none was
1973 * ever set or if the strategy is invalid
1974 */
1975 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001976 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001977 @Nullable
1978 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1979 @NonNull AudioProductStrategy strategy) {
1980 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1981 return devices.isEmpty() ? null : devices.get(0);
1982 }
1983
1984 /**
1985 * @hide
1986 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1987 * this audio strategy. Note that the devices may not be available at the time the preferred
1988 * devices is set, but it will be used once made available.
1989 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1990 * this preference for this strategy.</p>
1991 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1992 * devices used simultaneously to output the same audio signal.
1993 * @param strategy the audio strategy whose routing will be affected
1994 * @param devices a non-empty list of the audio devices to route to when available
1995 * @return true if the operation was successful, false otherwise
1996 */
1997 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00001998 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001999 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
2000 @NonNull List<AudioDeviceAttributes> devices) {
2001 Objects.requireNonNull(strategy);
2002 Objects.requireNonNull(devices);
2003 if (devices.isEmpty()) {
2004 throw new IllegalArgumentException(
2005 "Tried to set preferred devices for strategy with a empty list");
2006 }
2007 for (AudioDeviceAttributes device : devices) {
2008 Objects.requireNonNull(device);
2009 }
2010 try {
2011 final int status =
2012 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
2013 return status == AudioSystem.SUCCESS;
2014 } catch (RemoteException e) {
2015 throw e.rethrowFromSystemServer();
2016 }
2017 }
2018
2019 /**
2020 * @hide
2021 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002022 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07002023 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002024 * @param strategy the strategy to query
Paul Wang8ee29602022-12-22 03:40:19 +00002025 * @return list of the preferred devices for that strategy
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002026 */
2027 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002028 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002029 @NonNull
2030 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002031 @NonNull AudioProductStrategy strategy) {
2032 Objects.requireNonNull(strategy);
2033 try {
jiabinf40141d2020-08-07 17:27:48 -07002034 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002035 } catch (RemoteException e) {
2036 throw e.rethrowFromSystemServer();
2037 }
2038 }
2039
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002040 /**
2041 * @hide
Paul Wangee4774a2022-08-23 09:41:03 +00002042 * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by
2043 * this audio strategy.
2044 * <p>Use
2045 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2046 * to cancel setting this preference for this strategy.</p>
2047 * @param strategy the audio strategy whose routing will be affected
2048 * @param device the audio device to not route to when available
2049 * @return true if the operation was successful, false otherwise
2050 */
2051 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002052 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002053 public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2054 @NonNull AudioDeviceAttributes device) {
2055 Objects.requireNonNull(strategy);
2056 Objects.requireNonNull(device);
2057 try {
2058 final int status =
2059 getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2060 return status == AudioSystem.SUCCESS;
2061 } catch (RemoteException e) {
2062 throw e.rethrowFromSystemServer();
2063 }
2064 }
2065
2066 /**
2067 * @hide
2068 * Removes the audio device(s) from the non-default device list previously set with
2069 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2070 * @param strategy the audio strategy whose routing will be affected
2071 * @param device the audio device to remove from the non-default device list
2072 * @return true if the operation was successful, false otherwise (invalid strategy, or no
2073 * device set for example)
2074 */
2075 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002076 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002077 public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2078 @NonNull AudioDeviceAttributes device) {
2079 Objects.requireNonNull(strategy);
2080 Objects.requireNonNull(device);
2081 try {
2082 final int status =
2083 getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2084 return status == AudioSystem.SUCCESS;
2085 } catch (RemoteException e) {
2086 throw e.rethrowFromSystemServer();
2087 }
2088 }
2089
2090 /**
2091 * @hide
2092 * Gets the audio device(s) from the non-default device list previously set with
2093 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2094 * @param strategy the audio strategy to query
2095 * @return list of non-default devices for the strategy
2096 */
2097 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002098 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002099 @NonNull
2100 public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
2101 @NonNull AudioProductStrategy strategy) {
2102 Objects.requireNonNull(strategy);
2103 try {
2104 return getService().getNonDefaultDevicesForStrategy(strategy.getId());
2105 } catch (RemoteException e) {
2106 throw e.rethrowFromSystemServer();
2107 }
2108 }
2109
2110 /**
2111 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002112 * Interface to be notified of changes in the preferred audio device set for a given audio
2113 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08002114 * <p>Note that this listener will only be invoked whenever
2115 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07002116 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08002117 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2118 * preferred device. It will not be invoked directly after registration with
2119 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
2120 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002121 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002122 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
2123 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07002124 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002125 */
2126 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07002127 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002128 public interface OnPreferredDeviceForStrategyChangedListener {
2129 /**
2130 * Called on the listener to indicate that the preferred audio device for the given
2131 * strategy has changed.
2132 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2133 * @param device <code>null</code> if the preferred device was removed, or the newly set
2134 * preferred audio device
2135 */
2136 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08002137 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002138 }
2139
2140 /**
2141 * @hide
jiabinf40141d2020-08-07 17:27:48 -07002142 * Interface to be notified of changes in the preferred audio devices set for a given audio
2143 * strategy.
2144 * <p>Note that this listener will only be invoked whenever
Paul Wangee4774a2022-08-23 09:41:03 +00002145 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2146 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2147 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2148 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2149 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
jiabinf40141d2020-08-07 17:27:48 -07002150 * preferred device(s). It will not be invoked directly after registration with
2151 * {@link #addOnPreferredDevicesForStrategyChangedListener(
2152 * Executor, OnPreferredDevicesForStrategyChangedListener)}
2153 * to indicate which strategies had preferred devices at the time of registration.</p>
2154 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2155 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
2156 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07002157 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
2158 */
2159 @SystemApi
2160 public interface OnPreferredDevicesForStrategyChangedListener {
2161 /**
2162 * Called on the listener to indicate that the preferred audio devices for the given
2163 * strategy has changed.
2164 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2165 * @param devices a list of newly set preferred audio devices
2166 */
2167 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2168 @NonNull List<AudioDeviceAttributes> devices);
2169 }
2170
2171 /**
2172 * @hide
2173 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2174 * @param executor
2175 * @param listener
2176 * @throws SecurityException if the caller doesn't hold the required permission
2177 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
2178 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2179 */
2180 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002181 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002182 @Deprecated
2183 public void addOnPreferredDeviceForStrategyChangedListener(
2184 @NonNull @CallbackExecutor Executor executor,
2185 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
2186 throws SecurityException {
2187 // No-op, the method is deprecated.
2188 }
2189
2190 /**
2191 * @hide
2192 * Removes a previously added listener of changes to the strategy-preferred audio device.
2193 * @param listener
2194 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
2195 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2196 */
2197 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002198 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002199 @Deprecated
2200 public void removeOnPreferredDeviceForStrategyChangedListener(
2201 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
2202 // No-op, the method is deprecated.
2203 }
2204
2205 /**
2206 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002207 * Adds a listener for being notified of changes to the strategy-preferred audio device.
2208 * @param executor
2209 * @param listener
2210 * @throws SecurityException if the caller doesn't hold the required permission
2211 */
2212 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002213 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002214 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002215 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07002216 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002217 throws SecurityException {
2218 Objects.requireNonNull(executor);
2219 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002220 mPrefDevListenerMgr.addListener(
2221 executor, listener, "addOnPreferredDevicesForStrategyChangedListener",
2222 () -> new StrategyPreferredDevicesDispatcherStub());
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002223 }
2224
2225 /**
2226 * @hide
2227 * Removes a previously added listener of changes to the strategy-preferred audio device.
2228 * @param listener
2229 */
2230 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002231 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07002232 public void removeOnPreferredDevicesForStrategyChangedListener(
2233 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002234 Objects.requireNonNull(listener);
Paul Wang8ee29602022-12-22 03:40:19 +00002235 mPrefDevListenerMgr.removeListener(
2236 listener, "removeOnPreferredDevicesForStrategyChangedListener");
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002237 }
2238
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002239 /**
Paul Wangee4774a2022-08-23 09:41:03 +00002240 * @hide
2241 * Interface to be notified of changes in the non-default audio devices set for a given audio
2242 * strategy.
2243 * <p>Note that this listener will only be invoked whenever
2244 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2245 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2246 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2247 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2248 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2249 * non-default device(s). It will not be invoked directly after registration with
2250 * {@link #addOnNonDefaultDevicesForStrategyChangedListener(
2251 * Executor, OnNonDefaultDevicesForStrategyChangedListener)}
2252 * to indicate which strategies had preferred devices at the time of registration.</p>
2253 * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2254 * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2255 */
2256 @SystemApi
2257 public interface OnNonDefaultDevicesForStrategyChangedListener {
2258 /**
2259 * Called on the listener to indicate that the non-default audio devices for the given
2260 * strategy has changed.
2261 * @param strategy the {@link AudioProductStrategy} whose non-default device changed
2262 * @param devices a list of newly set non-default audio devices
2263 */
2264 void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2265 @NonNull List<AudioDeviceAttributes> devices);
2266 }
2267
2268 /**
2269 * @hide
2270 * Adds a listener for being notified of changes to the non-default audio devices for
2271 * strategies.
2272 * @param executor
2273 * @param listener
2274 * @throws SecurityException if the caller doesn't hold the required permission
2275 */
2276 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002277 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002278 public void addOnNonDefaultDevicesForStrategyChangedListener(
2279 @NonNull @CallbackExecutor Executor executor,
2280 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
2281 throws SecurityException {
2282 Objects.requireNonNull(executor);
2283 Objects.requireNonNull(listener);
2284
2285 mNonDefDevListenerMgr.addListener(
2286 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener",
2287 () -> new StrategyNonDefaultDevicesDispatcherStub());
2288 }
2289
2290 /**
2291 * @hide
2292 * Removes a previously added listener of changes to the non-default audio device for
2293 * strategies.
2294 * @param listener
2295 */
2296 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002297 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul Wangee4774a2022-08-23 09:41:03 +00002298 public void removeOnNonDefaultDevicesForStrategyChangedListener(
2299 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
2300 Objects.requireNonNull(listener);
2301 mNonDefDevListenerMgr.removeListener(
2302 listener, "removeOnNonDefaultDevicesForStrategyChangedListener");
2303 }
2304
2305 /**
Paul Wang8ee29602022-12-22 03:40:19 +00002306 * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the
2307 * StrategyPreferredDevicesDispatcherStub
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002308 */
Paul Wang8ee29602022-12-22 03:40:19 +00002309 private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener>
2310 mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002311
Paul Wangee4774a2022-08-23 09:41:03 +00002312 /**
2313 * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the
2314 * StrategyNonDefaultDevicesDispatcherStub
2315 */
2316 private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener>
2317 mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager();
2318
jiabinf40141d2020-08-07 17:27:48 -07002319 private final class StrategyPreferredDevicesDispatcherStub
Paul Wang8ee29602022-12-22 03:40:19 +00002320 extends IStrategyPreferredDevicesDispatcher.Stub
2321 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002322
2323 @Override
jiabinf40141d2020-08-07 17:27:48 -07002324 public void dispatchPrefDevicesChanged(int strategyId,
2325 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002326 final AudioProductStrategy strategy =
2327 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
Paul Wang8ee29602022-12-22 03:40:19 +00002328
2329 mPrefDevListenerMgr.callListeners(
2330 (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices));
2331 }
2332
2333 @Override
2334 public void register(boolean register) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002335 try {
Paul Wang8ee29602022-12-22 03:40:19 +00002336 if (register) {
2337 getService().registerStrategyPreferredDevicesDispatcher(this);
2338 } else {
2339 getService().unregisterStrategyPreferredDevicesDispatcher(this);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002340 }
Paul Wang8ee29602022-12-22 03:40:19 +00002341 } catch (RemoteException e) {
2342 e.rethrowFromSystemServer();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002343 }
2344 }
2345 }
2346
Paul Wangee4774a2022-08-23 09:41:03 +00002347 private final class StrategyNonDefaultDevicesDispatcherStub
2348 extends IStrategyNonDefaultDevicesDispatcher.Stub
2349 implements CallbackUtil.DispatcherStub {
2350
2351 @Override
2352 public void dispatchNonDefDevicesChanged(int strategyId,
2353 @NonNull List<AudioDeviceAttributes> devices) {
2354 final AudioProductStrategy strategy =
2355 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2356
2357 mNonDefDevListenerMgr.callListeners(
2358 (listener) -> listener.onNonDefaultDevicesForStrategyChanged(
2359 strategy, devices));
2360 }
2361
2362 @Override
2363 public void register(boolean register) {
2364 try {
2365 if (register) {
2366 getService().registerStrategyNonDefaultDevicesDispatcher(this);
2367 } else {
2368 getService().unregisterStrategyNonDefaultDevicesDispatcher(this);
2369 }
2370 } catch (RemoteException e) {
2371 e.rethrowFromSystemServer();
2372 }
2373 }
2374 }
2375
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002376 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002377 // Audio Capture Preset routing
2378
2379 /**
2380 * @hide
2381 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2382 * this capture preset. Note that the device may not be available at the time the preferred
2383 * device is set, but it will be used once made available.
2384 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2385 * for this capture preset.</p>
2386 * @param capturePreset the audio capture preset whose routing will be affected
2387 * @param device the audio device to route to when available
2388 * @return true if the operation was successful, false otherwise
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 setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002393 @NonNull AudioDeviceAttributes device) {
2394 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2395 }
2396
2397 /**
2398 * @hide
2399 * Remove all the preferred audio devices previously set
2400 * @param capturePreset the audio capture preset whose routing will be affected
2401 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2402 * device set for example)
2403 */
2404 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002405 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002406 public boolean clearPreferredDevicesForCapturePreset(
2407 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002408 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2409 return false;
2410 }
2411 try {
2412 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2413 return status == AudioSystem.SUCCESS;
2414 } catch (RemoteException e) {
2415 throw e.rethrowFromSystemServer();
2416 }
2417 }
2418
2419 /**
2420 * @hide
2421 * Return the preferred devices for an audio capture preset, previously set with
2422 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2423 * @param capturePreset the capture preset to query
2424 * @return a list that contains preferred devices for that capture preset.
2425 */
2426 @NonNull
2427 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002428 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002429 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2430 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002431 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2432 return new ArrayList<AudioDeviceAttributes>();
2433 }
2434 try {
2435 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2436 } catch (RemoteException e) {
2437 throw e.rethrowFromSystemServer();
2438 }
2439 }
2440
2441 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002442 @MediaRecorder.SystemSource int capturePreset,
2443 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002444 Objects.requireNonNull(devices);
2445 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2446 return false;
2447 }
2448 if (devices.size() != 1) {
2449 throw new IllegalArgumentException(
2450 "Only support setting one preferred devices for capture preset");
2451 }
2452 for (AudioDeviceAttributes device : devices) {
2453 Objects.requireNonNull(device);
2454 }
2455 try {
2456 final int status =
2457 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2458 return status == AudioSystem.SUCCESS;
2459 } catch (RemoteException e) {
2460 throw e.rethrowFromSystemServer();
2461 }
2462 }
2463
2464 /**
2465 * @hide
2466 * Interface to be notified of changes in the preferred audio devices set for a given capture
2467 * preset.
2468 * <p>Note that this listener will only be invoked whenever
2469 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2470 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2471 * preferred device. It will not be invoked directly after registration with
2472 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2473 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2474 * to indicate which strategies had preferred devices at the time of registration.</p>
2475 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2476 * @see #clearPreferredDevicesForCapturePreset(int)
2477 * @see #getPreferredDevicesForCapturePreset(int)
2478 */
2479 @SystemApi
2480 public interface OnPreferredDevicesForCapturePresetChangedListener {
2481 /**
2482 * Called on the listener to indicate that the preferred audio devices for the given
2483 * capture preset has changed.
2484 * @param capturePreset the capture preset whose preferred device changed
2485 * @param devices a list of newly set preferred audio devices
2486 */
2487 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002488 @MediaRecorder.SystemSource int capturePreset,
2489 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002490 }
2491
2492 /**
2493 * @hide
2494 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2495 * @param executor
2496 * @param listener
2497 * @throws SecurityException if the caller doesn't hold the required permission
2498 */
2499 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002500 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jiabin Huangb55305f2020-09-03 17:54:16 +00002501 public void addOnPreferredDevicesForCapturePresetChangedListener(
2502 @NonNull @CallbackExecutor Executor executor,
2503 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2504 throws SecurityException {
2505 Objects.requireNonNull(executor);
2506 Objects.requireNonNull(listener);
2507 int status = addOnDevRoleForCapturePresetChangedListener(
2508 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2509 if (status == AudioSystem.ERROR) {
2510 // This must not happen
2511 throw new RuntimeException("Unknown error happened");
2512 }
2513 if (status == AudioSystem.BAD_VALUE) {
2514 throw new IllegalArgumentException(
2515 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2516 + "on a previously registered listener");
2517 }
2518 }
2519
2520 /**
2521 * @hide
2522 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2523 * @param listener
2524 */
2525 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002526 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jiabin Huangb55305f2020-09-03 17:54:16 +00002527 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2528 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2529 Objects.requireNonNull(listener);
2530 int status = removeOnDevRoleForCapturePresetChangedListener(
2531 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2532 if (status == AudioSystem.ERROR) {
2533 // This must not happen
2534 throw new RuntimeException("Unknown error happened");
2535 }
2536 if (status == AudioSystem.BAD_VALUE) {
2537 throw new IllegalArgumentException(
2538 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2539 + "on an unregistered listener");
2540 }
2541 }
2542
2543 private <T> int addOnDevRoleForCapturePresetChangedListener(
2544 @NonNull @CallbackExecutor Executor executor,
2545 @NonNull T listener, int deviceRole) {
2546 Objects.requireNonNull(executor);
2547 Objects.requireNonNull(listener);
2548 DevRoleListeners<T> devRoleListeners =
2549 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2550 if (devRoleListeners == null) {
2551 return AudioSystem.ERROR;
2552 }
2553 synchronized (devRoleListeners.mDevRoleListenersLock) {
2554 if (devRoleListeners.hasDevRoleListener(listener)) {
2555 return AudioSystem.BAD_VALUE;
2556 }
2557 // lazy initialization of the list of device role listener
2558 if (devRoleListeners.mListenerInfos == null) {
2559 devRoleListeners.mListenerInfos = new ArrayList<>();
2560 }
2561 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2562 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2563 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2564 // register binder for callbacks
2565 synchronized (mDevRoleForCapturePresetListenersLock) {
2566 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2567 mDeviceRoleListenersStatus |= (1 << deviceRole);
2568 if (deviceRoleListenerStatus != 0) {
2569 // There are already device role changed listeners active.
2570 return AudioSystem.SUCCESS;
2571 }
2572 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2573 mDevicesRoleForCapturePresetDispatcherStub =
2574 new CapturePresetDevicesRoleDispatcherStub();
2575 }
2576 try {
2577 getService().registerCapturePresetDevicesRoleDispatcher(
2578 mDevicesRoleForCapturePresetDispatcherStub);
2579 } catch (RemoteException e) {
2580 throw e.rethrowFromSystemServer();
2581 }
2582 }
2583 }
2584 }
2585 return AudioSystem.SUCCESS;
2586 }
2587
2588 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2589 @NonNull T listener, int deviceRole) {
2590 Objects.requireNonNull(listener);
2591 DevRoleListeners<T> devRoleListeners =
2592 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2593 if (devRoleListeners == null) {
2594 return AudioSystem.ERROR;
2595 }
2596 synchronized (devRoleListeners.mDevRoleListenersLock) {
2597 if (!devRoleListeners.removeDevRoleListener(listener)) {
2598 return AudioSystem.BAD_VALUE;
2599 }
2600 if (devRoleListeners.mListenerInfos.size() == 0) {
2601 // unregister binder for callbacks
2602 synchronized (mDevRoleForCapturePresetListenersLock) {
2603 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2604 if (mDeviceRoleListenersStatus != 0) {
2605 // There are some other device role changed listeners active.
2606 return AudioSystem.SUCCESS;
2607 }
2608 try {
2609 getService().unregisterCapturePresetDevicesRoleDispatcher(
2610 mDevicesRoleForCapturePresetDispatcherStub);
2611 } catch (RemoteException e) {
2612 throw e.rethrowFromSystemServer();
2613 }
2614 }
2615 }
2616 }
2617 return AudioSystem.SUCCESS;
2618 }
2619
Cole Faust7da659b2022-10-15 21:33:29 -07002620 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of(
2621 AudioSystem.DEVICE_ROLE_PREFERRED,
2622 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
Jiabin Huangb55305f2020-09-03 17:54:16 +00002623
2624 private class DevRoleListenerInfo<T> {
2625 final @NonNull Executor mExecutor;
2626 final @NonNull T mListener;
2627 DevRoleListenerInfo(Executor executor, T listener) {
2628 mExecutor = executor;
2629 mListener = listener;
2630 }
2631 }
2632
2633 private class DevRoleListeners<T> {
2634 private final Object mDevRoleListenersLock = new Object();
2635 @GuardedBy("mDevRoleListenersLock")
2636 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2637
2638 @GuardedBy("mDevRoleListenersLock")
2639 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2640 if (mListenerInfos == null) {
2641 return null;
2642 }
2643 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2644 if (listenerInfo.mListener == listener) {
2645 return listenerInfo;
2646 }
2647 }
2648 return null;
2649 }
2650
2651 @GuardedBy("mDevRoleListenersLock")
2652 private boolean hasDevRoleListener(T listener) {
2653 return getDevRoleListenerInfo(listener) != null;
2654 }
2655
2656 @GuardedBy("mDevRoleListenersLock")
2657 private boolean removeDevRoleListener(T listener) {
2658 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2659 if (infoToRemove != null) {
2660 mListenerInfos.remove(infoToRemove);
2661 return true;
2662 }
2663 return false;
2664 }
2665 }
2666
2667 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2668 /**
2669 * Record if there is a listener added for device role change. If there is a listener added for
2670 * a specified device role change, the bit at position `1 << device_role` is set.
2671 */
2672 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2673 private int mDeviceRoleListenersStatus = 0;
2674 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2675 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2676
2677 private final class CapturePresetDevicesRoleDispatcherStub
2678 extends ICapturePresetDevicesRoleDispatcher.Stub {
2679
2680 @Override
2681 public void dispatchDevicesRoleChanged(
2682 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2683 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2684 if (listenersObj == null) {
2685 return;
2686 }
2687 switch (role) {
2688 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2689 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2690 listeners =
2691 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2692 listenersObj;
2693 final ArrayList<DevRoleListenerInfo<
2694 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2695 synchronized (listeners.mDevRoleListenersLock) {
2696 if (listeners.mListenerInfos.isEmpty()) {
2697 return;
2698 }
2699 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2700 OnPreferredDevicesForCapturePresetChangedListener>>)
2701 listeners.mListenerInfos.clone();
2702 }
2703 final long ident = Binder.clearCallingIdentity();
2704 try {
2705 for (DevRoleListenerInfo<
2706 OnPreferredDevicesForCapturePresetChangedListener> info :
2707 prefDevListeners) {
2708 info.mExecutor.execute(() ->
2709 info.mListener.onPreferredDevicesForCapturePresetChanged(
2710 capturePreset, devices));
2711 }
2712 } finally {
2713 Binder.restoreCallingIdentity(ident);
2714 }
2715 } break;
2716 default:
2717 break;
2718 }
2719 }
2720 }
2721
2722 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002723 // Direct playback query
2724
2725 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2726 direct playback not supported. */
2727 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2728 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2729 direct offload playback supported. Compressed offload is a variant of direct playback.
2730 It is the feature that allows audio processing tasks to be done on the Android device but
2731 not on the application processor, instead, it is handled by dedicated hardware such as audio
2732 DSPs. That will allow the application processor to be idle as much as possible, which is
2733 good for power saving. Compressed offload playback supports
2734 {@link AudioTrack.StreamEventCallback} for event notifications. */
2735 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2736 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2737 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2738 direct offload playback supported with gapless transitions. Compressed offload is a variant
2739 of direct playback. It is the feature that allows audio processing tasks to be done on the
2740 Android device but not on the application processor, instead, it is handled by dedicated
2741 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2742 possible, which is good for power saving. Compressed offload playback supports
2743 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2744 indicates the ability to play consecutive audio tracks without an audio silence in
2745 between. */
2746 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2747 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2748 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2749 direct playback supported. This value covers direct playback that is bitstream pass-through
2750 such as compressed pass-through. */
2751 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2752 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2753
2754 /** @hide */
2755 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2756 DIRECT_PLAYBACK_NOT_SUPPORTED,
2757 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2758 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2759 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2760 )
2761 @Retention(RetentionPolicy.SOURCE)
2762 public @interface AudioDirectPlaybackMode {}
2763
2764 /**
2765 * Returns a bitfield representing the different forms of direct playback currently available
2766 * for a given audio format.
2767 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2768 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2769 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2770 * passthrough.
2771 * <p>Checking for direct support can help the app select the representation of audio content
2772 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2773 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2774 * streams, if needed.
2775 * @param format the audio format (codec, sample rate, channels) being checked.
2776 * @param attributes the {@link AudioAttributes} to be used for playback
2777 * @return the direct playback mode available with given format and attributes. The returned
2778 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2779 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2780 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2781 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2782 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2783 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2784 */
2785 @AudioDirectPlaybackMode
2786 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2787 @NonNull AudioAttributes attributes) {
2788 Objects.requireNonNull(format);
2789 Objects.requireNonNull(attributes);
2790 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2791 }
2792
2793 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002794 // Offload query
2795 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002796 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002797 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2798 * is not competing with other software resources. In general, it is supported by dedicated
2799 * hardware, such as audio DSPs.
2800 * <p>Note that this query only provides information about the support of an audio format,
2801 * it does not indicate whether the resources necessary for the offloaded playback are
2802 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002803 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002804 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002805 * @return true if the given audio format can be offloaded.
2806 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002807 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2808 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002809 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002810 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002811 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002812 if (attributes == null) {
2813 throw new NullPointerException("Illegal null AudioAttributes");
2814 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002815 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2816 }
2817
2818 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2819 offload playback not supported */
2820 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2821 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2822 offload playback supported */
2823 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2824 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2825 offload playback supported with gapless transitions */
2826 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2827 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2828
2829 /** @hide */
2830 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2831 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2832 PLAYBACK_OFFLOAD_SUPPORTED,
2833 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2834 )
2835 @Retention(RetentionPolicy.SOURCE)
2836 public @interface AudioOffloadMode {}
2837
2838 /**
2839 * Returns whether offloaded playback of an audio format is supported on the device or not and
2840 * when supported whether gapless transitions are possible or not.
2841 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2842 * is not competing with other software resources. In general, it is supported by dedicated
2843 * hardware, such as audio DSPs.
2844 * <p>Note that this query only provides information about the support of an audio format,
2845 * it does not indicate whether the resources necessary for the offloaded playback are
2846 * available at that instant.
2847 * @param format the audio format (codec, sample rate, channels) being checked.
2848 * @param attributes the {@link AudioAttributes} to be used for playback
2849 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2850 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2851 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2852 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002853 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002854 */
jiabine22f6aa2021-12-10 01:09:02 +00002855 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002856 @AudioOffloadMode
2857 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2858 @NonNull AudioAttributes attributes) {
2859 if (format == null) {
2860 throw new NullPointerException("Illegal null AudioFormat");
2861 }
2862 if (attributes == null) {
2863 throw new NullPointerException("Illegal null AudioAttributes");
2864 }
2865 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002866 }
2867
2868 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002869 // Immersive audio
2870
2871 /**
2872 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002873 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002874 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2875 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002876 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002877 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002878 return new Spatializer(this);
2879 }
2880
2881 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002882 // Bluetooth SCO control
2883 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002884 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002885 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002886 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2887 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2888 *
2889 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002890 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002891 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002892 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002893 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2894 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2895 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002896
2897 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002898 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002899 * connection state has been updated.
2900 * <p>This intent has two extras:
2901 * <ul>
2902 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2903 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2904 * </ul>
2905 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2906 * <ul>
2907 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2908 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2909 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2910 * </ul>
2911 * @see #startBluetoothSco()
2912 */
2913 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2914 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2915 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2916
Eric Laurent3def1ee2010-03-17 23:26:26 -07002917 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002918 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2919 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002920 */
2921 public static final String EXTRA_SCO_AUDIO_STATE =
2922 "android.media.extra.SCO_AUDIO_STATE";
2923
2924 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002925 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2926 * bluetooth SCO connection state.
2927 */
2928 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2929 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2930
2931 /**
2932 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2933 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002934 */
2935 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2936 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002937 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2938 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002939 */
2940 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2941 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002942 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2943 * indicating that the SCO audio channel is being established
2944 */
2945 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2946 /**
2947 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002948 * there was an error trying to obtain the state
2949 */
2950 public static final int SCO_AUDIO_STATE_ERROR = -1;
2951
2952
2953 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002954 * Indicates if current platform supports use of SCO for off call use cases.
2955 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002956 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002957 * feature.
2958 * @return true if bluetooth SCO can be used for audio when not in call
2959 * false otherwise
2960 * @see #startBluetoothSco()
2961 */
2962 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002963 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002964 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2965 }
2966
2967 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002968 * Start bluetooth SCO audio connection.
2969 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00002970 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002971 * <p>This method can be used by applications wanting to send and received audio
2972 * to/from a bluetooth SCO headset while the phone is not in call.
2973 * <p>As the SCO connection establishment can take several seconds,
2974 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002975 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002976 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002977 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2978 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2979 * registration. If the state is already CONNECTED, no state change will be received via the
2980 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2981 * so that the connection stays active in case the current initiator stops the connection.
2982 * <p>Unless the connection is already active as described above, the state will always
2983 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2984 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2985 * <p>When finished with the SCO connection or if the establishment fails, the application must
2986 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002987 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2988 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002989 * <ul>
2990 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2991 * <li> the format must be mono </li>
2992 * <li> the sampling must be 16kHz or 8kHz </li>
2993 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002994 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002995 * <ul>
2996 * <li> the format must be mono </li>
2997 * <li> the sampling must be 8kHz </li>
2998 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002999 * <p>Note that the phone application always has the priority on the usage of the SCO
3000 * connection for telephony. If this method is called while the phone is in call
3001 * it will be ignored. Similarly, if a call is received or sent while an application
3002 * is using the SCO connection, the connection will be lost for the application and NOT
3003 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07003004 * <p>NOTE: up to and including API version
3005 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
3006 * voice call to the bluetooth headset.
3007 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
3008 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003009 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07003010 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurentf23f1b72022-02-18 10:57:54 +01003011 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003012 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01003013 @Deprecated public void startBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003014 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003015 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07003016 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07003017 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003018 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003019 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003020 }
3021 }
3022
3023 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003024 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07003025 * Start bluetooth SCO audio connection in virtual call mode.
3026 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003027 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent83900752014-05-15 15:14:22 -07003028 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
3029 * Telephony and communication applications (VoIP, Video Chat) should preferably select
3030 * virtual call mode.
3031 * Applications using voice input for search or commands should first try raw audio connection
3032 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
3033 * failure.
3034 * @see #startBluetoothSco()
3035 * @see #stopBluetoothSco()
3036 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
3037 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003038 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07003039 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003040 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07003041 try {
3042 service.startBluetoothScoVirtualCall(mICallBack);
3043 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003044 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07003045 }
3046 }
3047
3048 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07003049 * Stop bluetooth SCO audio connection.
3050 * <p>Requires Permission:
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003051 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003052 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003053 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
3054 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003055 * @see #startBluetoothSco()
Eric Laurentf23f1b72022-02-18 10:57:54 +01003056 * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead.
Eric Laurent3def1ee2010-03-17 23:26:26 -07003057 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07003058 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurentf23f1b72022-02-18 10:57:54 +01003059 @Deprecated public void stopBluetoothSco() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003060 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003061 try {
3062 service.stopBluetoothSco(mICallBack);
3063 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003064 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003065 }
3066 }
3067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 /**
Eric Laurenta553c252009-07-17 12:17:14 -07003069 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003070 * <p>
3071 * This method should only be used by applications that replace the platform-wide
3072 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003073 *
Eric Laurenta553c252009-07-17 12:17:14 -07003074 * @param on set <var>true</var> to use bluetooth SCO for communications;
3075 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 */
3077 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003078 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003079 try {
3080 service.setBluetoothScoOn(on);
3081 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003082 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07003083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003084 }
3085
3086 /**
Eric Laurenta553c252009-07-17 12:17:14 -07003087 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 *
Eric Laurenta553c252009-07-17 12:17:14 -07003089 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 * false if otherwise
Eric Laurentf23f1b72022-02-18 10:57:54 +01003091 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 */
Eric Laurentf23f1b72022-02-18 10:57:54 +01003093 @Deprecated public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003094 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003095 try {
3096 return service.isBluetoothScoOn();
3097 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003098 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07003099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 }
3101
3102 /**
Santiago Seifert1d8f6172022-08-25 14:34:44 +00003103 * @deprecated Use {@link MediaRouter#selectRoute} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 */
Eric Laurenta553c252009-07-17 12:17:14 -07003105 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003106 }
3107
3108 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08003109 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003110 *
Eric Laurentc117bea2017-02-07 11:04:18 -08003111 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07003112 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08003113 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114 */
3115 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07003116 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07003117 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3118 return true;
3119 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
3120 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3121 return true;
3122 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
3123 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07003124 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07003125 }
Eric Laurent9656df22016-04-20 16:42:28 -07003126 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003127 }
3128
3129 /**
3130 * Sets audio routing to the wired headset on or off.
3131 *
3132 * @param on set <var>true</var> to route audio to/from wired
3133 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07003134 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003135 */
Eric Laurenta553c252009-07-17 12:17:14 -07003136 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003137 }
3138
3139 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07003140 * Checks whether a wired headset is connected or not.
3141 * <p>This is not a valid indication that audio playback is
3142 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07003144 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08003146 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 */
3148 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08003149 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08003150 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08003151 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06003152 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
3153 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
3154 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07003155 return false;
3156 } else {
3157 return true;
3158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 }
3160
3161 /**
3162 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003163 * <p>
3164 * This method should only be used by applications that replace the platform-wide
3165 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 *
3167 * @param on set <var>true</var> to mute the microphone;
3168 * <var>false</var> to turn mute off
3169 */
Kenny Guy70e0c582015-06-30 19:18:28 +01003170 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003171 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04003172 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01003173 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00003174 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04003175 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003176 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04003177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003178 }
3179
3180 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003181 * @hide
3182 * Sets the microphone from switch mute on or off.
3183 * <p>
3184 * This method should only be used by InputManager to notify
3185 * Audio Subsystem about Microphone Mute switch state.
3186 *
3187 * @param on set <var>true</var> to mute the microphone;
3188 * <var>false</var> to turn mute off
3189 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003191 public void setMicrophoneMuteFromSwitch(boolean on) {
3192 final IAudioService service = getService();
3193 try {
3194 service.setMicrophoneMuteFromSwitch(on);
3195 } catch (RemoteException e) {
3196 throw e.rethrowFromSystemServer();
3197 }
3198 }
3199
3200 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 * Checks whether the microphone mute is on or off.
3202 *
3203 * @return true if microphone is muted, false if it's not
3204 */
3205 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07003206 final IAudioService service = getService();
3207 try {
3208 return service.isMicrophoneMuted();
3209 } catch (RemoteException e) {
3210 throw e.rethrowFromSystemServer();
3211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 }
3213
3214 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08003215 * Broadcast Action: microphone muting state changed.
3216 *
3217 * You <em>cannot</em> receive this through components declared
3218 * in manifests, only by explicitly registering for it with
3219 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3220 * Context.registerReceiver()}.
3221 *
3222 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
3223 * microphone is muted.
3224 */
3225 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3226 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
3227 "android.media.action.MICROPHONE_MUTE_CHANGED";
3228
3229 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07003230 * Broadcast Action: speakerphone state changed.
3231 *
3232 * You <em>cannot</em> receive this through components declared
3233 * in manifests, only by explicitly registering for it with
3234 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3235 * Context.registerReceiver()}.
3236 *
3237 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
3238 * speakerphone functionality is enabled or not.
3239 */
3240 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3241 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
3242 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
3243
3244 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07003246 * <p>
3247 * The audio mode encompasses audio routing AND the behavior of
3248 * the telephony layer. Therefore this method should only be used by applications that
3249 * replace the platform-wide management of audio settings or the main telephony application.
3250 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
3251 * application when it places a phone call, as it will cause signals from the radio layer
3252 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003253 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003254 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 * Informs the HAL about the current audio state so that
3256 * it can route the audio appropriately.
3257 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003258 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003259 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07003261 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003263 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 }
3265 }
3266
3267 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01003268 * This change id controls use of audio modes for call audio redirection.
3269 * @hide
3270 */
3271 @ChangeId
3272 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
3273 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
3274
3275 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003276 * Returns the current audio mode.
3277 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003278 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003279 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003280 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003282 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003284 int mode = service.getMode();
3285 int sdk;
3286 try {
3287 sdk = getContext().getApplicationInfo().targetSdkVersion;
3288 } catch (NullPointerException e) {
3289 // some tests don't have a Context
3290 sdk = Build.VERSION.SDK_INT;
3291 }
3292 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3293 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01003294 } else if (mode == MODE_CALL_REDIRECT
3295 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3296 mode = MODE_IN_CALL;
3297 } else if (mode == MODE_COMMUNICATION_REDIRECT
3298 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3299 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003300 }
3301 return mode;
3302 } catch (RemoteException e) {
3303 throw e.rethrowFromSystemServer();
3304 }
3305 }
3306
3307 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003308 * Interface definition of a callback that is notified when the audio mode changes
3309 */
3310 public interface OnModeChangedListener {
3311 /**
3312 * Called on the listener to indicate that the audio mode has changed
3313 *
3314 * @param mode The current audio mode
3315 */
3316 void onModeChanged(@AudioMode int mode);
3317 }
3318
Nate Myren08635fe2021-04-20 12:04:39 -07003319 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003320 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003321 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003322 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3323 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003324
Nate Myren08635fe2021-04-20 12:04:39 -07003325
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003326 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3327 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003328
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003329 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003330 public void register(boolean register) {
3331 try {
3332 if (register) {
3333 getService().registerModeDispatcher(this);
3334 } else {
3335 getService().unregisterModeDispatcher(this);
3336 }
3337 } catch (RemoteException e) {
3338 e.rethrowFromSystemServer();
3339 }
3340 }
Nate Myren08635fe2021-04-20 12:04:39 -07003341
3342 @Override
3343 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003344 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003345 }
3346 }
3347
Nate Myren08635fe2021-04-20 12:04:39 -07003348 /**
3349 * Adds a listener to be notified of changes to the audio mode.
3350 * See {@link #getMode()}
3351 * @param executor
3352 * @param listener
3353 */
3354 public void addOnModeChangedListener(
3355 @NonNull @CallbackExecutor Executor executor,
3356 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003357 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3358 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003359 }
3360
3361 /**
3362 * Removes a previously added listener for changes to audio mode.
3363 * See {@link #getMode()}
3364 * @param listener
3365 */
3366 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003367 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003368 }
3369
3370 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003371 * Indicates if the platform supports a special call screening and call monitoring mode.
3372 * <p>
3373 * When this mode is supported, it is possible to perform call screening and monitoring
3374 * functions while other use cases like music or movie playback are active.
3375 * <p>
3376 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3377 * call screening mode.
3378 * <p>
3379 * If call screening mode is not supported, setting mode to
3380 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3381 * {@link #getMode()}.
3382 * @return true if call screening mode is supported, false otherwise.
3383 */
3384 public boolean isCallScreeningModeSupported() {
3385 final IAudioService service = getService();
3386 try {
3387 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003388 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003389 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003390 }
3391 }
3392
3393 /* modes for setMode/getMode/setRoute/getRoute */
3394 /**
3395 * Audio harware modes.
3396 */
3397 /**
3398 * Invalid audio mode.
3399 */
3400 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3401 /**
3402 * Current audio mode. Used to apply audio routing to current mode.
3403 */
3404 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3405 /**
3406 * Normal audio mode: not ringing and no call established.
3407 */
3408 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3409 /**
3410 * Ringing audio mode. An incoming is being signaled.
3411 */
3412 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3413 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003414 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003415 */
3416 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003417 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003418 * In communication audio mode. An audio/video chat or VoIP call is established.
3419 */
3420 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003421 /**
3422 * Call screening in progress. Call is connected and audio is accessible to call
3423 * screening applications but other audio use cases are still possible.
3424 */
3425 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3426
Eric Laurent1c3408f2021-11-09 12:09:54 +01003427 /**
3428 * A telephony call is established and its audio is being redirected to another device.
3429 */
3430 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3431
3432 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003433 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003434 * device.
3435 */
3436 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3437
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003438 /** @hide */
3439 @IntDef(flag = false, prefix = "MODE_", value = {
3440 MODE_NORMAL,
3441 MODE_RINGTONE,
3442 MODE_IN_CALL,
3443 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003444 MODE_CALL_SCREENING,
3445 MODE_CALL_REDIRECT,
3446 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003447 )
3448 @Retention(RetentionPolicy.SOURCE)
3449 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003450
3451 /* Routing bits for setRouting/getRouting API */
3452 /**
3453 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003454 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3455 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 */
Eric Laurenta553c252009-07-17 12:17:14 -07003457 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003459 * Routing audio output to speaker
3460 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3461 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 */
Eric Laurenta553c252009-07-17 12:17:14 -07003463 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003464 /**
3465 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003466 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3467 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468 */
3469 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3470 /**
3471 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003472 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3473 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 */
Eric Laurenta553c252009-07-17 12:17:14 -07003475 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 /**
3477 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003478 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3479 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003480 */
Eric Laurenta553c252009-07-17 12:17:14 -07003481 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003482 /**
3483 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003484 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3485 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 */
Eric Laurenta553c252009-07-17 12:17:14 -07003487 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 /**
3489 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003490 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3491 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003492 */
Eric Laurenta553c252009-07-17 12:17:14 -07003493 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494
3495 /**
3496 * Sets the audio routing for a specified mode
3497 *
3498 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3499 * @param routes bit vector of routes requested, created from one or
3500 * more of ROUTE_xxx types. Set bits indicate that route should be on
3501 * @param mask bit vector of routes to change, created from one or more of
3502 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003503 *
3504 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003505 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 */
Eric Laurenta553c252009-07-17 12:17:14 -07003507 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003508 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 }
3510
3511 /**
3512 * Returns the current audio routing bit vector for a specified mode.
3513 *
3514 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3515 * @return an audio route bit vector that can be compared with ROUTE_xxx
3516 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003517 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3518 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003520 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003522 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 }
3524
3525 /**
3526 * Checks whether any music is active.
3527 *
3528 * @return true if any music tracks are active.
3529 */
3530 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003531 final IAudioService service = getService();
3532 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003533 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003534 } catch (RemoteException e) {
3535 throw e.rethrowFromSystemServer();
3536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 }
3538
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003539 /**
3540 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003541 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3542 * display). Note that BT audio sinks are not considered remote devices.
3543 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3544 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003545 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003546 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003547 final IAudioService service = getService();
3548 try {
3549 return service.isMusicActive(true /*remotely*/);
3550 } catch (RemoteException e) {
3551 throw e.rethrowFromSystemServer();
3552 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003553 }
3554
3555 /**
3556 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003557 * Checks whether the current audio focus is exclusive.
3558 * @return true if the top of the audio focus stack requested focus
3559 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3560 */
3561 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003562 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003563 try {
3564 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3565 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003566 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003567 }
3568 }
3569
3570 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003571 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003572 * An audio session identifier is a system wide unique identifier for a set of audio streams
3573 * (one or more mixed together).
3574 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3575 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3576 * session ID will be applied to the mixed audio content of the players that share the same
3577 * audio session.
3578 * <p>This method can for instance be used when creating one of the
3579 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3580 * or to specify a session for a speech synthesis utterance
3581 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003582 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003583 * system failed to generate a new session, a condition in which audio playback or recording
3584 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003585 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003586 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003587 int session = AudioSystem.newAudioSessionId();
3588 if (session > 0) {
3589 return session;
3590 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003591 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003592 return ERROR;
3593 }
3594 }
3595
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003596 /**
3597 * A special audio session ID to indicate that the audio session ID isn't known and the
3598 * framework should generate a new value. This can be used when building a new
3599 * {@link AudioTrack} instance with
3600 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3601 */
3602 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3603
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003605 /*
3606 * Sets a generic audio configuration parameter. The use of these parameters
3607 * are platform dependant, see libaudio
3608 *
3609 * ** Temporary interface - DO NOT USE
3610 *
3611 * TODO: Replace with a more generic key:value get/set mechanism
3612 *
3613 * param key name of parameter to set. Must not be null.
3614 * param value value of parameter. Must not be null.
3615 */
3616 /**
3617 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003618 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 */
Eric Laurenta553c252009-07-17 12:17:14 -07003620 @Deprecated public void setParameter(String key, String value) {
3621 setParameters(key+"="+value);
3622 }
3623
3624 /**
3625 * Sets a variable number of parameter values to audio hardware.
3626 *
3627 * @param keyValuePairs list of parameters key value pairs in the form:
3628 * key1=value1;key2=value2;...
3629 *
3630 */
3631 public void setParameters(String keyValuePairs) {
3632 AudioSystem.setParameters(keyValuePairs);
3633 }
3634
3635 /**
William Escandeef429b62021-10-15 18:37:40 +02003636 * @hide
3637 */
3638 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003639 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003640 public void setHfpEnabled(boolean enable) {
3641 AudioSystem.setParameters("hfp_enable=" + enable);
3642 }
3643
3644 /**
3645 * @hide
3646 */
3647 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003648 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003649 public void setHfpVolume(int volume) {
3650 AudioSystem.setParameters("hfp_volume=" + volume);
3651 }
3652
3653 /**
3654 * @hide
3655 */
3656 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003657 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003658 public void setHfpSamplingRate(int rate) {
3659 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3660 }
3661
3662 /**
3663 * @hide
3664 */
3665 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003666 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003667 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3668 boolean hasWbsEnabled) {
3669 AudioSystem.setParameters("bt_headset_name=" + name
3670 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3671 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3672 }
3673
3674 /**
3675 * @hide
3676 */
3677 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003678 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
William Escandeef429b62021-10-15 18:37:40 +02003679 public void setA2dpSuspended(boolean enable) {
3680 AudioSystem.setParameters("A2dpSuspended=" + enable);
3681 }
3682
3683 /**
Rahul Sabnis215e5412022-12-21 16:03:07 -08003684 * Suspends the use of LE Audio.
3685 *
3686 * @param enable {@code true} to suspend le audio, {@code false} to unsuspend
3687 *
3688 * @hide
3689 */
3690 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00003691 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
Rahul Sabnis215e5412022-12-21 16:03:07 -08003692 public void setLeAudioSuspended(boolean enable) {
3693 AudioSystem.setParameters("LeAudioSuspended=" + enable);
3694 }
3695
3696 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003697 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003698 *
3699 * @param keys list of parameters
3700 * @return list of parameters key value pairs in the form:
3701 * key1=value1;key2=value2;...
3702 */
3703 public String getParameters(String keys) {
3704 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 }
3706
3707 /* Sound effect identifiers */
3708 /**
3709 * Keyboard and direction pad click sound
3710 * @see #playSoundEffect(int)
3711 */
3712 public static final int FX_KEY_CLICK = 0;
3713 /**
3714 * Focus has moved up
3715 * @see #playSoundEffect(int)
3716 */
3717 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3718 /**
3719 * Focus has moved down
3720 * @see #playSoundEffect(int)
3721 */
3722 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3723 /**
3724 * Focus has moved left
3725 * @see #playSoundEffect(int)
3726 */
3727 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3728 /**
3729 * Focus has moved right
3730 * @see #playSoundEffect(int)
3731 */
3732 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3733 /**
3734 * IME standard keypress sound
3735 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003736 */
3737 public static final int FX_KEYPRESS_STANDARD = 5;
3738 /**
3739 * IME spacebar keypress sound
3740 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741 */
3742 public static final int FX_KEYPRESS_SPACEBAR = 6;
3743 /**
3744 * IME delete keypress sound
3745 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 */
3747 public static final int FX_KEYPRESS_DELETE = 7;
3748 /**
3749 * IME return_keypress sound
3750 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 */
3752 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003753
3754 /**
3755 * Invalid keypress sound
3756 * @see #playSoundEffect(int)
3757 */
3758 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003759
3760 /**
3761 * Back sound
3762 * @see #playSoundEffect(int)
3763 */
3764 public static final int FX_BACK = 10;
3765
3766 /**
3767 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003768 * <p>
3769 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3770 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003771 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3772 * @see #playSoundEffect(int)
3773 */
3774 public static final int FX_HOME = 11;
3775
3776 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003777 * @hide Navigation repeat sound 1
3778 * <p>
3779 * To be played by the framework when a focus navigation is repeatedly triggered
3780 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003781 * This is currently only used on TV devices.
3782 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3783 * @see #playSoundEffect(int)
3784 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003785 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003786
3787 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003788 * @hide Navigation repeat sound 2
3789 * <p>
3790 * To be played by the framework when a focus navigation is repeatedly triggered
3791 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003792 * This is currently only used on TV devices.
3793 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3794 * @see #playSoundEffect(int)
3795 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003796 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003797
3798 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003799 * @hide Navigation repeat sound 3
3800 * <p>
3801 * To be played by the framework when a focus navigation is repeatedly triggered
3802 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003803 * This is currently only used on TV devices.
3804 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3805 * @see #playSoundEffect(int)
3806 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003807 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003808
3809 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003810 * @hide Navigation repeat sound 4
3811 * <p>
3812 * To be played by the framework when a focus navigation is repeatedly triggered
3813 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003814 * This is currently only used on TV devices.
3815 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3816 * @see #playSoundEffect(int)
3817 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003818 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 /**
3821 * @hide Number of sound effects
3822 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003823 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003824 public static final int NUM_SOUND_EFFECTS = 16;
3825
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003826 /** @hide */
3827 @IntDef(prefix = { "FX_" }, value = {
3828 FX_KEY_CLICK,
3829 FX_FOCUS_NAVIGATION_UP,
3830 FX_FOCUS_NAVIGATION_DOWN,
3831 FX_FOCUS_NAVIGATION_LEFT,
3832 FX_FOCUS_NAVIGATION_RIGHT,
3833 FX_KEYPRESS_STANDARD,
3834 FX_KEYPRESS_SPACEBAR,
3835 FX_KEYPRESS_DELETE,
3836 FX_KEYPRESS_RETURN,
3837 FX_KEYPRESS_INVALID,
3838 FX_BACK
3839 })
3840 @Retention(RetentionPolicy.SOURCE)
3841 public @interface SystemSoundEffect {}
3842
Philip Junker7f1fdff2020-12-03 16:10:41 +01003843 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003844 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003845 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003846 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003847
3848 /**
3849 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003850 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3851 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003852 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003853 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003854 switch (n) {
3855 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003856 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003857 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003858 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003859 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003860 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003861 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003862 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003863 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003864 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003865 return -1;
3866 }
3867 }
3868
3869 /**
3870 * @hide
3871 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003872 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003873 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003874 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003875 } catch (RemoteException e) {
3876
3877 }
3878 }
3879
3880 /**
3881 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003882 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003883 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003884 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003885 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003886 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003887 } catch (RemoteException e) {
3888 throw e.rethrowFromSystemServer();
3889 }
3890 }
3891
3892 /**
3893 * @hide
3894 * @param enabled
3895 */
3896 public void setHomeSoundEffectEnabled(boolean enabled) {
3897 try {
3898 getService().setHomeSoundEffectEnabled(enabled);
3899 } catch (RemoteException e) {
3900
3901 }
3902 }
3903
3904 /**
3905 * @hide
3906 * @return true if the home sound effect is enabled
3907 */
3908 public boolean isHomeSoundEffectEnabled() {
3909 try {
3910 return getService().isHomeSoundEffectEnabled();
3911 } catch (RemoteException e) {
3912 throw e.rethrowFromSystemServer();
3913 }
3914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003915
3916 /**
3917 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003918 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 * NOTE: This version uses the UI settings to determine
3920 * whether sounds are heard or not.
3921 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003922 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003923 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003924 }
3925
3926 /**
3927 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003928 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003929 * @param userId The current user to pull sound settings from
3930 * NOTE: This version uses the UI settings to determine
3931 * whether sounds are heard or not.
3932 * @hide
3933 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003934 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003935 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3936 return;
3937 }
3938
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003939 if (delegateSoundEffectToVdm(effectType)) {
3940 return;
3941 }
3942
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003943 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003944 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003945 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003946 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003947 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003948 }
3949 }
3950
3951 /**
3952 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003953 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003954 * @param volume Sound effect volume.
3955 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3956 * 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 -08003957 * NOTE: This version is for applications that have their own
3958 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003959 */
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003960 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003961 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3962 return;
3963 }
3964
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003965 if (delegateSoundEffectToVdm(effectType)) {
3966 return;
3967 }
3968
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003969 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003970 try {
3971 service.playSoundEffectVolume(effectType, volume);
3972 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003973 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003974 }
3975 }
3976
3977 /**
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003978 * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice}
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003979 * configured with custom device policy for audio. If there is such device, request to play
3980 * sound effect is forwarded to {@link VirtualDeviceManager}.
3981 *
3982 * @param effectType - The type of sound effect.
3983 * @return true if the request was forwarded to {@link VirtualDeviceManager} instance,
3984 * false otherwise.
3985 */
3986 private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003987 if (hasCustomPolicyVirtualDeviceContext()) {
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003988 VirtualDeviceManager vdm = getVirtualDeviceManager();
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003989 vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
3990 return true;
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01003991 }
3992 return false;
3993 }
3994
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00003995 private boolean hasCustomPolicyVirtualDeviceContext() {
3996 if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) {
3997 return false;
3998 }
3999
4000 VirtualDeviceManager vdm = getVirtualDeviceManager();
4001 return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO)
4002 != DEVICE_POLICY_DEFAULT;
4003 }
4004
Jan Sebechlebskyfb48c022022-12-16 16:26:47 +01004005 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004006 * Load Sound effects.
4007 * This method must be called when sound effects are enabled.
4008 */
4009 public void loadSoundEffects() {
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.loadSoundEffects();
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
4018 /**
4019 * Unload Sound effects.
4020 * This method can be called to free some memory when
4021 * sound effects are disabled.
4022 */
4023 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004024 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004025 try {
4026 service.unloadSoundEffects();
4027 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004028 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029 }
4030 }
4031
Eric Laurent4050c932009-07-08 02:52:14 -07004032 /**
Andy Hung69836952020-03-26 01:00:15 -07004033 * @hide
4034 */
4035 public static String audioFocusToString(int focus) {
4036 switch (focus) {
4037 case AUDIOFOCUS_NONE:
4038 return "AUDIOFOCUS_NONE";
4039 case AUDIOFOCUS_GAIN:
4040 return "AUDIOFOCUS_GAIN";
4041 case AUDIOFOCUS_GAIN_TRANSIENT:
4042 return "AUDIOFOCUS_GAIN_TRANSIENT";
4043 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
4044 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
4045 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
4046 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
4047 case AUDIOFOCUS_LOSS:
4048 return "AUDIOFOCUS_LOSS";
4049 case AUDIOFOCUS_LOSS_TRANSIENT:
4050 return "AUDIOFOCUS_LOSS_TRANSIENT";
4051 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
4052 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
4053 default:
4054 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
4055 }
4056 }
4057
4058 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08004059 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004060 */
4061 public static final int AUDIOFOCUS_NONE = 0;
4062
4063 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004064 * 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 -07004065 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004066 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004067 */
4068 public static final int AUDIOFOCUS_GAIN = 1;
4069 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004070 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
4071 * amount of time. Examples of temporary changes are the playback of driving directions, or an
4072 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004073 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004074 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004075 */
4076 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004077 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004078 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004079 * amount of time, and where it is acceptable for other audio applications to keep playing
4080 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004081 * Examples of temporary changes are the playback of driving directions where playback of music
4082 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004083 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004084 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4085 */
4086 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
4087 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004088 * Used to indicate a temporary request of audio focus, anticipated to last a short
4089 * amount of time, during which no other applications, or system components, should play
4090 * anything. Examples of exclusive and transient audio focus requests are voice
4091 * memo recording and speech recognition, during which the system shouldn't play any
4092 * notifications, and media playback should have paused.
4093 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4094 */
4095 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
4096 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004097 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004098 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004099 */
4100 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
4101 /**
4102 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004103 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004104 */
4105 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
4106 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004107 * 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 -07004108 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
4109 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004110 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004111 */
4112 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
4113 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004114
4115 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004116 * Interface definition for a callback to be invoked when the audio focus of the system is
4117 * updated.
4118 */
4119 public interface OnAudioFocusChangeListener {
4120 /**
4121 * Called on the listener to notify it the audio focus for this listener has been changed.
4122 * The focusChange value indicates whether the focus was gained,
4123 * whether the focus was lost, and whether that loss is transient, or whether the new focus
4124 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004125 * When losing focus, listeners can use the focus change information to decide what
4126 * behavior to adopt when losing focus. A music player could for instance elect to lower
4127 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
4128 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004129 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004130 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004131 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07004132 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004133 }
4134
4135 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004136 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
4137 */
4138 private static class FocusRequestInfo {
4139 @NonNull final AudioFocusRequest mRequest;
4140 @Nullable final Handler mHandler;
4141 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
4142 mRequest = afr;
4143 mHandler = handler;
4144 }
4145 }
4146
4147 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004148 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
4149 * to actual listener objects.
4150 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01004151 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004152 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
4153 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004154
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004155 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004156 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004157 }
4158
4159 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004160 * Handler for events (audio focus change, recording config change) coming from the
4161 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004162 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004163 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004164 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004165
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004166 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004167 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004168 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004169 private final static int MSSG_FOCUS_CHANGE = 0;
4170 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004171 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004172
4173 /**
4174 * Helper class to handle the forwarding of audio service events to the appropriate listener
4175 */
4176 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004177 private final Handler mHandler;
4178
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004179 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004180 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004181 if (handler == null) {
4182 if ((looper = Looper.myLooper()) == null) {
4183 looper = Looper.getMainLooper();
4184 }
4185 } else {
4186 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004187 }
4188
4189 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004190 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004191 mHandler = new Handler(looper) {
4192 @Override
4193 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004194 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004195 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004196 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
4197 if (fri != null) {
4198 final OnAudioFocusChangeListener listener =
4199 fri.mRequest.getOnAudioFocusChangeListener();
4200 if (listener != null) {
4201 Log.d(TAG, "dispatching onAudioFocusChange("
4202 + msg.arg1 + ") to " + msg.obj);
4203 listener.onAudioFocusChange(msg.arg1);
4204 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004205 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004206 } break;
4207 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08004208 final RecordConfigChangeCallbackData cbData =
4209 (RecordConfigChangeCallbackData) msg.obj;
4210 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07004211 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004212 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004213 } break;
4214 case MSSG_PLAYBACK_CONFIG_CHANGE: {
4215 final PlaybackConfigChangeCallbackData cbData =
4216 (PlaybackConfigChangeCallbackData) msg.obj;
4217 if (cbData.mCb != null) {
4218 if (DEBUG) {
4219 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
4220 }
4221 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
4222 }
4223 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08004224 default:
4225 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004226 }
4227 }
4228 };
4229 } else {
4230 mHandler = null;
4231 }
4232 }
4233
4234 Handler getHandler() {
4235 return mHandler;
4236 }
4237 }
4238
Glenn Kasten30c918c2011-11-10 17:56:41 -08004239 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004240 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004241 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004242 final FocusRequestInfo fri = findFocusRequestInfo(id);
4243 if (fri != null) {
4244 final OnAudioFocusChangeListener listener =
4245 fri.mRequest.getOnAudioFocusChangeListener();
4246 if (listener != null) {
4247 final Handler h = (fri.mHandler == null) ?
4248 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
4249 final Message m = h.obtainMessage(
4250 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
4251 id/*obj*/);
4252 h.sendMessage(m);
4253 }
4254 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004255 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004256
4257 @Override
4258 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
4259 synchronized (mFocusRequestsLock) {
4260 // TODO use generation counter as the key instead
4261 final BlockingFocusResultReceiver focusReceiver =
4262 mFocusRequestsAwaitingResult.remove(clientId);
4263 if (focusReceiver != null) {
4264 focusReceiver.notifyResult(requestResult);
4265 } else {
4266 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
4267 }
4268 }
4269 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004270 };
4271
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004272 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004273 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07004274 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004275 } else {
4276 return new String(this.toString() + l.toString());
4277 }
4278 }
4279
4280 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004281 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004282 * Registers a listener to be called when audio focus changes and keeps track of the associated
4283 * focus request (including Handler to use for the listener).
4284 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004285 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004286 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
4287 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
4288 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
4289 new ServiceEventHandlerDelegate(h).getHandler());
4290 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4291 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004292 }
4293
4294 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07004295 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004296 * Causes the specified listener to not be called anymore when focus is gained or lost.
4297 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004298 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004299 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004300 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004301 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004302 }
4303
4304
4305 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004306 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004307 */
4308 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
4309 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004310 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004311 */
4312 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004313 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004314 * A focus change request whose granting is delayed: the request was successful, but the
4315 * requester will only be granted audio focus once the condition that prevented immediate
4316 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004317 * See {@link #requestAudioFocus(AudioFocusRequest)} and
4318 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004319 */
4320 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004321
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004322 /** @hide */
4323 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
4324 AUDIOFOCUS_REQUEST_FAILED,
4325 AUDIOFOCUS_REQUEST_GRANTED,
4326 AUDIOFOCUS_REQUEST_DELAYED }
4327 )
4328 @Retention(RetentionPolicy.SOURCE)
4329 public @interface FocusRequestResult {}
4330
4331 /**
4332 * @hide
4333 * code returned when a synchronous focus request on the client-side is to be blocked
4334 * until the external audio focus policy decides on the response for the client
4335 */
4336 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
4337
4338 /**
4339 * Timeout duration in ms when waiting on an external focus policy for the result for a
4340 * focus request
4341 */
Weilin Xu1017d432022-06-08 00:27:52 +00004342 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004343
4344 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4345
4346 private final Object mFocusRequestsLock = new Object();
4347 /**
4348 * Map of all receivers of focus request results, one per unresolved focus request.
4349 * Receivers are added before sending the request to the external focus policy,
4350 * and are removed either after receiving the result, or after the timeout.
4351 * This variable is lazily initialized.
4352 */
4353 @GuardedBy("mFocusRequestsLock")
4354 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4355
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004356
4357 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004358 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004359 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004360 * @param l the listener to be notified of audio focus changes
4361 * @param streamType the main audio stream type affected by the focus request
4362 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4363 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004364 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004365 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4366 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004367 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4368 * that benefits from the system not playing disruptive sounds like notifications, for
4369 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004370 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004371 * as the playback of a song or a video.
4372 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004373 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004374 */
4375 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004376 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4377 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004378 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004379
4380 try {
4381 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4382 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4383 // AUDIOFOCUS_FLAG_DELAY_OK flag
4384 status = requestAudioFocus(l,
4385 new AudioAttributes.Builder()
4386 .setInternalLegacyStreamType(streamType).build(),
4387 durationHint,
4388 0 /* flags, legacy behavior */);
4389 } catch (IllegalArgumentException e) {
4390 Log.e(TAG, "Audio focus request denied due to ", e);
4391 }
4392
4393 return status;
4394 }
4395
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004396 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004397 /**
4398 * @hide
4399 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4400 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4401 * the system is in a state where focus cannot change, but be granted focus later when
4402 * this condition ends.
4403 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004404 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004405 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004406 /**
4407 * @hide
4408 * Use this flag when requesting audio focus to indicate that the requester
4409 * will pause its media playback (if applicable) when losing audio focus with
4410 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4411 * <br>On some platforms, the ducking may be handled without the application being aware of it
4412 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4413 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4414 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4415 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004416 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004417 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4418 /**
4419 * @hide
4420 * Use this flag to lock audio focus so granting is temporarily disabled.
4421 * <br>This flag can only be used by owners of a registered
4422 * {@link android.media.audiopolicy.AudioPolicy} in
4423 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4424 */
4425 @SystemApi
4426 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004427
4428 /**
4429 * @hide
4430 * flag set on test API calls,
4431 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004432 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004433 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004434 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004435 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4436 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004437 /** @hide */
4438 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004439 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004440
4441 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004442 * Request audio focus.
4443 * See the {@link AudioFocusRequest} for information about the options available to configure
4444 * your request, and notification of focus gain and loss.
4445 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4446 * requested.
4447 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4448 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4449 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4450 * is requested without building the {@link AudioFocusRequest} with
4451 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4452 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004453 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004454 */
4455 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004456 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004457 }
4458
4459 /**
4460 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4461 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4462 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4463 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4464 * @throws IllegalArgumentException if passed a null argument
4465 */
4466 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4467 if (focusRequest == null) {
4468 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4469 }
4470 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4471 focusRequest.getAudioAttributes());
4472 }
4473
4474 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004475 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004476 * Request audio focus.
4477 * Send a request to obtain the audio focus. This method differs from
4478 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4479 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004480 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4481 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4482 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4483 * requesting audio focus.
4484 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4485 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4486 * for the playback of driving directions, or notifications sounds.
4487 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4488 * the previous focus owner to keep playing if it ducks its audio output.
4489 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4490 * that benefits from the system not playing disruptive sounds like notifications, for
4491 * usecases such as voice memo recording, or speech recognition.
4492 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4493 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004494 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4495 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004496 * <br>Use 0 when not using any flags for the request, which behaves like
4497 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4498 * focus is granted immediately, or the grant request fails because the system is in a
4499 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004500 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4501 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4502 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4503 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4504 * @throws IllegalArgumentException
4505 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004506 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004507 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004508 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004509 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004510 int durationHint,
4511 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004512 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4513 throw new IllegalArgumentException("Invalid flags 0x"
4514 + Integer.toHexString(flags).toUpperCase());
4515 }
4516 return requestAudioFocus(l, requestAttributes, durationHint,
4517 flags & AUDIOFOCUS_FLAGS_APPS,
4518 null /* no AudioPolicy*/);
4519 }
4520
4521 /**
4522 * @hide
4523 * Request or lock audio focus.
4524 * This method is to be used by system components that have registered an
4525 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4526 * so focus granting is temporarily disabled.
4527 * @param l see the description of the same parameter in
4528 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4529 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4530 * requesting audio focus.
4531 * @param durationHint see the description of the same parameter in
4532 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4533 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004534 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004535 * <br>Use 0 when not using any flags for the request, which behaves like
4536 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4537 * focus is granted immediately, or the grant request fails because the system is in a
4538 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004539 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4540 * focus, or null.
4541 * @return see the description of the same return value in
4542 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4543 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004544 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004545 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004546 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004547 @RequiresPermission(anyOf= {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004548 Manifest.permission.MODIFY_PHONE_STATE,
4549 Manifest.permission.MODIFY_AUDIO_ROUTING
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004550 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004551 public int requestAudioFocus(OnAudioFocusChangeListener l,
4552 @NonNull AudioAttributes requestAttributes,
4553 int durationHint,
4554 int flags,
4555 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004556 // parameter checking
4557 if (requestAttributes == null) {
4558 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4559 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004560 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004561 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004562 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004563 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004564 throw new IllegalArgumentException("Illegal flags 0x"
4565 + Integer.toHexString(flags).toUpperCase());
4566 }
4567 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4568 throw new IllegalArgumentException(
4569 "Illegal null focus listener when flagged as accepting delayed focus grant");
4570 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004571 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4572 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4573 throw new IllegalArgumentException(
4574 "Illegal null focus listener when flagged as pausing instead of ducking");
4575 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004576 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4577 throw new IllegalArgumentException(
4578 "Illegal null audio policy when locking audio focus");
4579 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004580
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004581 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004582 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004583 .setAudioAttributes(requestAttributes)
4584 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4585 == AUDIOFOCUS_FLAG_DELAY_OK)
4586 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4587 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4588 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4589 .build();
4590 return requestAudioFocus(afr, ap);
4591 }
4592
4593 /**
4594 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004595 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4596 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4597 * @param afr the parameters of the request
4598 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4599 * @param clientFakeUid the UID of the client, here an arbitrary int,
4600 * doesn't have to be a real UID
4601 * @param clientTargetSdk the target SDK used by the client
4602 * @return return code indicating status of the request
4603 */
4604 @TestApi
4605 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4606 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4607 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4608 Objects.requireNonNull(afr);
4609 Objects.requireNonNull(clientFakeId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004610 int status;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004611 try {
Oscar Azucena3209c342022-05-13 19:08:14 -07004612 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004613 afr.getFocusGain(),
4614 mICallBack,
4615 mAudioFocusDispatcher,
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004616 clientFakeId, "com.android.test.fakeclient",
4617 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4618 clientFakeUid, clientTargetSdk);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004619 } catch (RemoteException e) {
4620 throw e.rethrowFromSystemServer();
4621 }
Weilin Xu1017d432022-06-08 00:27:52 +00004622 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4623 // default path with no external focus policy
4624 return status;
4625 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004626
Weilin Xu1017d432022-06-08 00:27:52 +00004627 BlockingFocusResultReceiver focusReceiver;
4628 synchronized (mFocusRequestsLock) {
4629 focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
4630 }
4631
4632 return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004633 }
4634
4635 /**
4636 * @hide
4637 * Test API to abandon audio focus for an arbitrary client.
4638 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4639 * @param afr the parameters used for the request
4640 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4641 * would be requesting
4642 * @return return code indicating status of the request
4643 */
4644 @TestApi
4645 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4646 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4647 @NonNull String clientFakeId) {
4648 Objects.requireNonNull(afr);
4649 Objects.requireNonNull(clientFakeId);
4650 try {
4651 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4652 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4653 } catch (RemoteException e) {
4654 throw e.rethrowFromSystemServer();
4655 }
4656 }
4657
4658 /**
4659 * @hide
4660 * Return the duration of the fade out applied when a player of the given AudioAttributes
4661 * is losing audio focus
4662 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4663 * @return a duration in ms, 0 indicates no fade out is applied
4664 */
4665 @TestApi
4666 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4667 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4668 {
4669 Objects.requireNonNull(aa);
4670 try {
4671 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4672 } catch (RemoteException e) {
4673 throw e.rethrowFromSystemServer();
4674 }
4675 }
4676
4677 /**
4678 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004679 * Request or lock audio focus.
4680 * This method is to be used by system components that have registered an
4681 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4682 * so focus granting is temporarily disabled.
4683 * @param afr see the description of the same parameter in
4684 * {@link #requestAudioFocus(AudioFocusRequest)}
4685 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4686 * focus, or null.
4687 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4688 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4689 * @throws NullPointerException if the AudioFocusRequest is null
4690 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4691 */
4692 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004693 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004694 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4695 if (afr == null) {
4696 throw new NullPointerException("Illegal null AudioFocusRequest");
4697 }
4698 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4699 if (afr.locksFocus() && ap == null) {
4700 throw new IllegalArgumentException(
4701 "Illegal null audio policy when locking audio focus");
4702 }
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004703
4704 if (hasCustomPolicyVirtualDeviceContext()) {
4705 // If the focus request was made within context associated with VirtualDevice
4706 // configured with custom device policy for audio, bypass audio service focus handling.
4707 // The custom device policy for audio means that audio associated with this device
4708 // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice
4709 // shouldn't affect non-virtual audio tracks (and vice versa).
4710 return AUDIOFOCUS_REQUEST_GRANTED;
4711 }
4712
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004713 registerAudioFocusRequest(afr);
4714 final IAudioService service = getService();
4715 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004716 int sdk;
4717 try {
4718 sdk = getContext().getApplicationInfo().targetSdkVersion;
4719 } catch (NullPointerException e) {
4720 // some tests don't have a Context
4721 sdk = Build.VERSION.SDK_INT;
4722 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004723
4724 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
Weilin Xu1017d432022-06-08 00:27:52 +00004725 BlockingFocusResultReceiver focusReceiver;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004726 synchronized (mFocusRequestsLock) {
Weilin Xu1017d432022-06-08 00:27:52 +00004727
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004728 try {
4729 // TODO status contains result and generation counter for ext policy
4730 status = service.requestAudioFocus(afr.getAudioAttributes(),
4731 afr.getFocusGain(), mICallBack,
4732 mAudioFocusDispatcher,
4733 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004734 getContext().getOpPackageName() /* package name */,
4735 getContext().getAttributionTag(),
4736 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004737 ap != null ? ap.cb() : null,
4738 sdk);
4739 } catch (RemoteException e) {
4740 throw e.rethrowFromSystemServer();
4741 }
Weilin Xu1017d432022-06-08 00:27:52 +00004742 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4743 // default path with no external focus policy
4744 return status;
4745 }
4746 focusReceiver = addClientIdToFocusReceiverLocked(clientId);
Oscar Azucena3209c342022-05-13 19:08:14 -07004747 }
4748
Weilin Xu1017d432022-06-08 00:27:52 +00004749 return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver);
4750 }
4751
4752 @GuardedBy("mFocusRequestsLock")
4753 private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) {
4754 BlockingFocusResultReceiver focusReceiver;
4755 if (mFocusRequestsAwaitingResult == null) {
4756 mFocusRequestsAwaitingResult =
4757 new HashMap<String, BlockingFocusResultReceiver>(1);
4758 }
4759 focusReceiver = new BlockingFocusResultReceiver(clientId);
4760 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
4761 return focusReceiver;
Oscar Azucena3209c342022-05-13 19:08:14 -07004762 }
4763
4764 private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
Weilin Xu1017d432022-06-08 00:27:52 +00004765 BlockingFocusResultReceiver focusReceiver) {
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004766 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4767 if (DEBUG && !focusReceiver.receivedResult()) {
Oscar Azucena3209c342022-05-13 19:08:14 -07004768 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
4769 + " response from ext policy timed out, denying request");
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004770 }
Oscar Azucena3209c342022-05-13 19:08:14 -07004771
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004772 synchronized (mFocusRequestsLock) {
4773 mFocusRequestsAwaitingResult.remove(clientId);
4774 }
4775 return focusReceiver.requestResult();
4776 }
4777
4778 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4779 private static final class SafeWaitObject {
4780 private boolean mQuit = false;
4781
4782 public void safeNotify() {
4783 synchronized (this) {
4784 mQuit = true;
4785 this.notify();
4786 }
4787 }
4788
4789 public void safeWait(long millis) throws InterruptedException {
4790 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4791 synchronized (this) {
4792 while (!mQuit) {
4793 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4794 if (timeToWait < 0) { break; }
4795 this.wait(timeToWait);
4796 }
4797 }
4798 }
4799 }
4800
4801 private static final class BlockingFocusResultReceiver {
4802 private final SafeWaitObject mLock = new SafeWaitObject();
4803 @GuardedBy("mLock")
4804 private boolean mResultReceived = false;
4805 // request denied by default (e.g. timeout)
4806 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4807 private final String mFocusClientId;
4808
4809 BlockingFocusResultReceiver(String clientId) {
4810 mFocusClientId = clientId;
4811 }
4812
4813 boolean receivedResult() { return mResultReceived; }
4814 int requestResult() { return mFocusRequestResult; }
4815
4816 void notifyResult(int requestResult) {
4817 synchronized (mLock) {
4818 mResultReceived = true;
4819 mFocusRequestResult = requestResult;
4820 mLock.safeNotify();
4821 }
4822 }
4823
4824 public void waitForResult(long timeOutMs) {
4825 synchronized (mLock) {
4826 if (mResultReceived) {
4827 // the result was received before waiting
4828 return;
4829 }
4830 try {
4831 mLock.safeWait(timeOutMs);
4832 } catch (InterruptedException e) { }
4833 }
4834 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004835 }
4836
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004837 /**
4838 * @hide
4839 * Used internally by telephony package to request audio focus. Will cause the focus request
4840 * to be associated with the "voice communication" identifier only used in AudioService
4841 * to identify this use case.
4842 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4843 * the establishment of the call
4844 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4845 * media applications resume after a call
4846 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004847 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004848 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004849 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004850 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004851 service.requestAudioFocus(new AudioAttributes.Builder()
4852 .setInternalLegacyStreamType(streamType).build(),
4853 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004854 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004855 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004856 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004857 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004858 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004859 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004860 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004861 }
4862 }
4863
4864 /**
4865 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004866 * Return the volume ramping time for a sound to be played after the given focus request,
4867 * and to play a sound of the given attributes
4868 * @param focusGain
4869 * @param attr
4870 * @return
4871 */
4872 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004873 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004874 try {
4875 return service.getFocusRampTimeMs(focusGain, attr);
4876 } catch (RemoteException e) {
4877 throw e.rethrowFromSystemServer();
4878 }
4879 }
4880
4881 /**
4882 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004883 * Set the result to the audio focus request received through
4884 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4885 * @param afi the information about the focus requester
4886 * @param requestResult the result to the focus request to be passed to the requester
4887 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4888 */
4889 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004890 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004891 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4892 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4893 if (afi == null) {
4894 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4895 }
4896 if (ap == null) {
4897 throw new IllegalArgumentException("Illegal null AudioPolicy");
4898 }
4899 final IAudioService service = getService();
4900 try {
4901 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4902 } catch (RemoteException e) {
4903 throw e.rethrowFromSystemServer();
4904 }
4905 }
4906
4907 /**
4908 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004909 * Notifies an application with a focus listener of gain or loss of audio focus.
4910 * This method can only be used by owners of an {@link AudioPolicy} configured with
4911 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4912 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4913 * that was received by the {@code AudioPolicy} through
4914 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4915 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4916 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4917 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4918 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4919 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4920 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4921 * <br>For the focus gain, the change type should be the same as the app requested.
4922 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4923 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4924 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4925 * if there was an error sending the request.
4926 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4927 */
4928 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00004929 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004930 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4931 @NonNull AudioPolicy ap) {
4932 if (afi == null) {
4933 throw new NullPointerException("Illegal null AudioFocusInfo");
4934 }
4935 if (ap == null) {
4936 throw new NullPointerException("Illegal null AudioPolicy");
4937 }
4938 final IAudioService service = getService();
4939 try {
4940 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4941 } catch (RemoteException e) {
4942 throw e.rethrowFromSystemServer();
4943 }
4944 }
4945
4946 /**
4947 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004948 * Used internally by telephony package to abandon audio focus, typically after a call or
4949 * when ringing ends and the call is rejected or not answered.
4950 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4951 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004952 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004953 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004954 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004955 try {
John Spurlock61560172015-02-06 19:46:04 -05004956 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004957 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004958 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004959 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004960 }
4961 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004962
4963 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004964 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4965 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004966 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004967 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004968 */
4969 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004970 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4971 }
4972
4973 /**
4974 * @hide
4975 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4976 * @param l the listener with which focus was requested.
4977 * @param aa the {@link AudioAttributes} with which audio focus was requested
4978 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004979 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004980 */
4981 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004982 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4983 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004984 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004985 if (hasCustomPolicyVirtualDeviceContext()) {
4986 // If this AudioManager instance is running within VirtualDevice context configured
4987 // with custom device policy for audio, the audio focus handling is bypassed.
4988 return AUDIOFOCUS_REQUEST_GRANTED;
4989 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004990 unregisterAudioFocusRequest(l);
4991 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004992 try {
Ján Sebechlebskýdcc49642023-02-07 10:20:59 +00004993 return service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004994 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004995 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004996 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004997 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004998 }
4999
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005000 //====================================================================
5001 // Remote Control
5002 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07005003 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005004 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5005 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005006 * in the application manifest. The package of the component must match that of
5007 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07005008 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005009 */
RoboErikb214efb2014-07-24 13:20:30 -07005010 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005011 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005012 if (eventReceiver == null) {
5013 return;
5014 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005015 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005016 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
5017 "receiver and context package names don't match");
5018 return;
5019 }
5020 // construct a PendingIntent for the media button and register it
5021 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5022 // the associated intent will be handled by the component being registered
5023 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07005024 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07005025 0/*requestCode, ignored*/, mediaButtonIntent,
5026 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005027 registerMediaButtonIntent(pi, eventReceiver);
5028 }
5029
5030 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07005031 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
5032 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
5033 * the buttons to go to any PendingIntent. Note that you should only use this form if
5034 * you know you will continue running for the full time until unregistering the
5035 * PendingIntent.
5036 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07005037 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
5038 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
5039 * media button that was pressed.
5040 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07005041 */
RoboErikb214efb2014-07-24 13:20:30 -07005042 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07005043 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
5044 if (eventReceiver == null) {
5045 return;
5046 }
5047 registerMediaButtonIntent(eventReceiver, null);
5048 }
5049
5050 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005051 * @hide
5052 * no-op if (pi == null) or (eventReceiver == null)
5053 */
5054 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07005055 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005056 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
5057 return;
5058 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005059 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
5060 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07005061 }
5062
5063 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07005064 * Unregister the receiver of MEDIA_BUTTON intents.
5065 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5066 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07005067 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005068 */
RoboErikb214efb2014-07-24 13:20:30 -07005069 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005070 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005071 if (eventReceiver == null) {
5072 return;
5073 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005074 // construct a PendingIntent for the media button and unregister it
5075 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5076 // the associated intent will be handled by the component being registered
5077 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07005078 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07005079 0/*requestCode, ignored*/, mediaButtonIntent,
5080 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005081 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005082 }
5083
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005084 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07005085 * Unregister the receiver of MEDIA_BUTTON intents.
5086 * @param eventReceiver same PendingIntent that was registed with
5087 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07005088 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07005089 */
RoboErikb214efb2014-07-24 13:20:30 -07005090 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07005091 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
5092 if (eventReceiver == null) {
5093 return;
5094 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005095 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07005096 }
5097
5098 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005099 * @hide
5100 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07005101 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07005102 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07005103 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005104 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07005105
5106 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07005107 * Registers the remote control client for providing information to display on the remote
5108 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07005109 * @param rcClient The remote control client from which remote controls will receive
5110 * information to display.
5111 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07005112 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005113 */
RoboErikb214efb2014-07-24 13:20:30 -07005114 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005115 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005116 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005117 return;
5118 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005119 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005120 }
5121
5122 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07005123 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07005124 * remote controls.
5125 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005126 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07005127 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005128 */
RoboErikb214efb2014-07-24 13:20:30 -07005129 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005130 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07005131 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005132 return;
5133 }
Marco Nelissen29f16932015-04-17 09:50:56 -07005134 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005135 }
5136
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07005137 /**
RoboErika66c40b2014-08-15 15:21:41 -07005138 * Registers a {@link RemoteController} instance for it to receive media
5139 * metadata updates and playback state information from applications using
5140 * {@link RemoteControlClient}, and control their playback.
5141 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05005142 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07005143 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005144 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07005145 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07005146 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07005147 * @return true if the {@link RemoteController} was successfully registered,
5148 * false if an error occurred, due to an internal system error, or
5149 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07005150 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07005151 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
5152 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005153 */
RoboErikb214efb2014-07-24 13:20:30 -07005154 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005155 public boolean registerRemoteController(RemoteController rctlr) {
5156 if (rctlr == null) {
5157 return false;
5158 }
RoboErik430fc482014-06-12 15:49:20 -07005159 rctlr.startListeningToSessions();
5160 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005161 }
5162
5163 /**
RoboErika66c40b2014-08-15 15:21:41 -07005164 * Unregisters a {@link RemoteController}, causing it to no longer receive
5165 * media metadata and playback state information, and no longer be capable
5166 * of controlling playback.
5167 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07005168 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07005169 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07005170 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
5171 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005172 */
RoboErikb214efb2014-07-24 13:20:30 -07005173 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005174 public void unregisterRemoteController(RemoteController rctlr) {
5175 if (rctlr == null) {
5176 return;
5177 }
RoboErik430fc482014-06-12 15:49:20 -07005178 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005179 }
5180
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005181
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005182 //====================================================================
5183 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005184 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005185 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005186 * Register the given {@link AudioPolicy}.
5187 * This call is synchronous and blocks until the registration process successfully completed
5188 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005189 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005190 * @return {@link #ERROR} if there was an error communicating with the registration service
5191 * or if the user doesn't have the required
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005192 * {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005193 * {@link #SUCCESS} otherwise.
5194 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005195 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005196 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005197 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005198 return registerAudioPolicyStatic(policy);
5199 }
5200
5201 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005202 if (policy == null) {
5203 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5204 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005205 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005206 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005207 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005208 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07005209 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
5210 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08005211 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005212 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005213 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005214 } else {
5215 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005216 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005217 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005218 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005219 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005220 }
5221 return SUCCESS;
5222 }
5223
5224 /**
5225 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005226 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005227 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005228 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005229 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005230 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005231 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05005232 unregisterAudioPolicyAsyncStatic(policy);
5233 }
5234
5235 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005236 if (policy == null) {
5237 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5238 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005239 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005240 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005241 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005242 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005243 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005244 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005245 }
5246 }
5247
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005248 /**
5249 * @hide
5250 * Unregisters an {@link AudioPolicy} synchronously.
5251 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
5252 * associated with mixes of this policy.
5253 * @param policy the non-null {@link AudioPolicy} to unregister.
5254 */
5255 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00005256 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005257 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
5258 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
5259 final IAudioService service = getService();
5260 try {
5261 policy.invalidateCaptorsAndInjectors();
5262 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07005263 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08005264 } catch (RemoteException e) {
5265 throw e.rethrowFromSystemServer();
5266 }
5267 }
5268
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07005269 /**
5270 * @hide
5271 * @return true if an AudioPolicy was previously registered
5272 */
5273 @TestApi
5274 public boolean hasRegisteredDynamicPolicy() {
5275 final IAudioService service = getService();
5276 try {
5277 return service.hasRegisteredDynamicPolicy();
5278 } catch (RemoteException e) {
5279 throw e.rethrowFromSystemServer();
5280 }
5281 }
5282
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005283 //====================================================================
5284 // Notification of playback activity & playback configuration
5285 /**
5286 * Interface for receiving update notifications about the playback activity on the system.
5287 * Extend this abstract class and register it with
5288 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
5289 * to be notified.
5290 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
5291 * configuration.
5292 * @see AudioPlaybackConfiguration
5293 */
5294 public static abstract class AudioPlaybackCallback {
5295 /**
5296 * Called whenever the playback activity and configuration has changed.
5297 * @param configs list containing the results of
5298 * {@link AudioManager#getActivePlaybackConfigurations()}.
5299 */
5300 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
5301 }
5302
5303 private static class AudioPlaybackCallbackInfo {
5304 final AudioPlaybackCallback mCb;
5305 final Handler mHandler;
5306 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
5307 mCb = cb;
5308 mHandler = handler;
5309 }
5310 }
5311
5312 private final static class PlaybackConfigChangeCallbackData {
5313 final AudioPlaybackCallback mCb;
5314 final List<AudioPlaybackConfiguration> mConfigs;
5315
5316 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
5317 List<AudioPlaybackConfiguration> configs) {
5318 mCb = cb;
5319 mConfigs = configs;
5320 }
5321 }
5322
5323 /**
5324 * Register a callback to be notified of audio playback changes through
5325 * {@link AudioPlaybackCallback}
5326 * @param cb non-null callback to register
5327 * @param handler the {@link Handler} object for the thread on which to execute
5328 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5329 * {@link Looper} will be used.
5330 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005331 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
5332 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005333 {
5334 if (cb == null) {
5335 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5336 }
5337
5338 synchronized(mPlaybackCallbackLock) {
5339 // lazy initialization of the list of playback callbacks
5340 if (mPlaybackCallbackList == null) {
5341 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
5342 }
5343 final int oldCbCount = mPlaybackCallbackList.size();
5344 if (!hasPlaybackCallback_sync(cb)) {
5345 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
5346 new ServiceEventHandlerDelegate(handler).getHandler()));
5347 final int newCbCount = mPlaybackCallbackList.size();
5348 if ((oldCbCount == 0) && (newCbCount > 0)) {
5349 // register binder for callbacks
5350 try {
5351 getService().registerPlaybackCallback(mPlayCb);
5352 } catch (RemoteException e) {
5353 throw e.rethrowFromSystemServer();
5354 }
5355 }
5356 } else {
5357 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
5358 + "registered callback");
5359 }
5360 }
5361 }
5362
5363 /**
5364 * Unregister an audio playback callback previously registered with
5365 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5366 * @param cb non-null callback to unregister
5367 */
5368 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
5369 if (cb == null) {
5370 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5371 }
5372 synchronized(mPlaybackCallbackLock) {
5373 if (mPlaybackCallbackList == null) {
5374 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5375 + " that was never registered");
5376 return;
5377 }
5378 final int oldCbCount = mPlaybackCallbackList.size();
5379 if (removePlaybackCallback_sync(cb)) {
5380 final int newCbCount = mPlaybackCallbackList.size();
5381 if ((oldCbCount > 0) && (newCbCount == 0)) {
5382 // unregister binder for callbacks
5383 try {
5384 getService().unregisterPlaybackCallback(mPlayCb);
5385 } catch (RemoteException e) {
5386 throw e.rethrowFromSystemServer();
5387 }
5388 }
5389 } else {
5390 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5391 + " already unregistered or never registered");
5392 }
5393 }
5394 }
5395
5396 /**
5397 * Returns the current active audio playback configurations of the device
5398 * @return a non-null list of playback configurations. An empty list indicates there is no
5399 * playback active when queried.
5400 * @see AudioPlaybackConfiguration
5401 */
5402 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5403 final IAudioService service = getService();
5404 try {
5405 return service.getActivePlaybackConfigurations();
5406 } catch (RemoteException e) {
5407 throw e.rethrowFromSystemServer();
5408 }
5409 }
5410
5411 /**
5412 * All operations on this list are sync'd on mPlaybackCallbackLock.
5413 * List is lazy-initialized in
5414 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5415 * List can be null.
5416 */
5417 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5418 private final Object mPlaybackCallbackLock = new Object();
5419
5420 /**
5421 * Must be called synchronized on mPlaybackCallbackLock
5422 */
5423 private boolean hasPlaybackCallback_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 return true;
5428 }
5429 }
5430 }
5431 return false;
5432 }
5433
5434 /**
5435 * Must be called synchronized on mPlaybackCallbackLock
5436 */
5437 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5438 if (mPlaybackCallbackList != null) {
5439 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5440 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5441 mPlaybackCallbackList.remove(i);
5442 return true;
5443 }
5444 }
5445 }
5446 return false;
5447 }
5448
5449 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005450 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005451 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5452 boolean flush) {
5453 if (flush) {
5454 Binder.flushPendingCommands();
5455 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005456 synchronized(mPlaybackCallbackLock) {
5457 if (mPlaybackCallbackList != null) {
5458 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5459 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5460 if (arci.mHandler != null) {
5461 final Message m = arci.mHandler.obtainMessage(
5462 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5463 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5464 arci.mHandler.sendMessage(m);
5465 }
5466 }
5467 }
5468 }
5469 }
5470
5471 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005472
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005473 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005474 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005475 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005476 * Interface for receiving update notifications about the recording configuration. Extend
5477 * this abstract class and register it with
5478 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5479 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005480 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5481 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005482 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005483 */
5484 public static abstract class AudioRecordingCallback {
5485 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005486 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005487 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005488 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005489 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005490 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005491 }
5492
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005493 private static class AudioRecordingCallbackInfo {
5494 final AudioRecordingCallback mCb;
5495 final Handler mHandler;
5496 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5497 mCb = cb;
5498 mHandler = handler;
5499 }
5500 }
5501
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005502 private final static class RecordConfigChangeCallbackData {
5503 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005504 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005505
5506 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005507 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005508 mCb = cb;
5509 mConfigs = configs;
5510 }
5511 }
5512
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005513 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005514 * Register a callback to be notified of audio recording changes through
5515 * {@link AudioRecordingCallback}
5516 * @param cb non-null callback to register
5517 * @param handler the {@link Handler} object for the thread on which to execute
5518 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5519 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005520 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005521 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5522 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005523 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005524 if (cb == null) {
5525 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5526 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005527
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005528 synchronized(mRecordCallbackLock) {
5529 // lazy initialization of the list of recording callbacks
5530 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005531 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005532 }
5533 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005534 if (!hasRecordCallback_sync(cb)) {
5535 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5536 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005537 final int newCbCount = mRecordCallbackList.size();
5538 if ((oldCbCount == 0) && (newCbCount > 0)) {
5539 // register binder for callbacks
5540 final IAudioService service = getService();
5541 try {
5542 service.registerRecordingCallback(mRecCb);
5543 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005544 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005545 }
5546 }
5547 } else {
5548 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5549 + "registered callback");
5550 }
5551 }
5552 }
5553
5554 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005555 * Unregister an audio recording callback previously registered with
5556 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5557 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005558 */
5559 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5560 if (cb == null) {
5561 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5562 }
5563 synchronized(mRecordCallbackLock) {
5564 if (mRecordCallbackList == null) {
5565 return;
5566 }
5567 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005568 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005569 final int newCbCount = mRecordCallbackList.size();
5570 if ((oldCbCount > 0) && (newCbCount == 0)) {
5571 // unregister binder for callbacks
5572 final IAudioService service = getService();
5573 try {
5574 service.unregisterRecordingCallback(mRecCb);
5575 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005576 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005577 }
5578 }
5579 } else {
5580 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5581 + " already unregistered or never registered");
5582 }
5583 }
5584 }
5585
5586 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005587 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005588 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005589 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005590 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005591 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005592 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005593 final IAudioService service = getService();
5594 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005595 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005596 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005597 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005598 }
5599 }
5600
5601 /**
5602 * constants for the recording events, to keep in sync
5603 * with frameworks/av/include/media/AudioPolicy.h
5604 */
5605 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005606 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005607 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005608 public static final int RECORD_CONFIG_EVENT_START = 0;
5609 /** @hide */
5610 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5611 /** @hide */
5612 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5613 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005614 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005615 /**
5616 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5617 */
5618 /** @hide */
5619 public static final int RECORD_RIID_INVALID = -1;
5620 /** @hide */
5621 public static final int RECORDER_STATE_STARTED = 0;
5622 /** @hide */
5623 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005624
5625 /**
5626 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005627 * List is lazy-initialized in
5628 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005629 * List can be null.
5630 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005631 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005632 private final Object mRecordCallbackLock = new Object();
5633
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005634 /**
5635 * Must be called synchronized on mRecordCallbackLock
5636 */
5637 private boolean hasRecordCallback_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 return true;
5642 }
5643 }
5644 }
5645 return false;
5646 }
5647
5648 /**
5649 * Must be called synchronized on mRecordCallbackLock
5650 */
5651 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5652 if (mRecordCallbackList != null) {
5653 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5654 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5655 mRecordCallbackList.remove(i);
5656 return true;
5657 }
5658 }
5659 }
5660 return false;
5661 }
5662
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005663 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005664 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005665 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005666 synchronized(mRecordCallbackLock) {
5667 if (mRecordCallbackList != null) {
5668 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5669 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5670 if (arci.mHandler != null) {
5671 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005672 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5673 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005674 arci.mHandler.sendMessage(m);
5675 }
5676 }
5677 }
5678 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005679 }
5680
5681 };
5682
5683 //=====================================================================
5684
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005685 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005686 * @hide
5687 * Reload audio settings. This method is called by Settings backup
5688 * agent when audio settings are restored and causes the AudioService
5689 * to read and apply restored settings.
5690 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005691 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005692 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005693 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005694 try {
5695 service.reloadAudioSettings();
5696 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005697 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005698 }
5699 }
5700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005701 /**
5702 * {@hide}
5703 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005704 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005705
5706 /**
5707 * Checks whether the phone is in silent mode, with or without vibrate.
5708 *
5709 * @return true if phone is in silent mode, with or without vibrate.
5710 *
5711 * @see #getRingerMode()
5712 *
5713 * @hide pending API Council approval
5714 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005715 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005716 public boolean isSilentMode() {
5717 int ringerMode = getRingerMode();
5718 boolean silentMode =
5719 (ringerMode == RINGER_MODE_SILENT) ||
5720 (ringerMode == RINGER_MODE_VIBRATE);
5721 return silentMode;
5722 }
5723
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005724 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5725 // class is not used by other parts of the framework, which instead use definitions and methods
5726 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5727
Eric Laurent948d3272014-05-16 15:18:45 -07005728 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005729 * The audio device code for representing "no device." */
5730 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5731 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005732 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005733 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5734 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5735 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5736 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005737 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005738 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005739 /** @hide
5740 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005741 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005742 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005743 /** @hide
5744 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005745 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005746 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005747 /** @hide
5748 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005749 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005750 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005751 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005752 * The audio output device code for a USB headphone with attached microphone */
5753 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5754 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005755 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005756 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005757 /** @hide
5758 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5759 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005760 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005761 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005762 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5763 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005764 /** @hide
5765 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005766 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5767 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005768 /** @hide
5769 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005770 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005771 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005772 /** @hide
5773 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005774 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005775 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5776 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005777 /** @hide
5778 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005779 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005780 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5781 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005782 /** @hide
5783 * The audio output device code for S/PDIF (legacy) or HDMI
5784 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005785 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005786 /** @hide
5787 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005788 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005789 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5790 /** @hide
5791 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005792 * docking station
5793 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005794 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005795 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005796 /** @hide
5797 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005798 * docking station
5799 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005800 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005801 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005802 /** @hide
5803 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005804 * mode and the Android device in USB device mode
5805 */
5806 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005807 /** @hide
5808 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005809 * mode and the Android device in USB host mode
5810 */
5811 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005812 /** @hide
5813 * The audio output device code for projection output.
5814 */
5815 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5816 /** @hide
5817 * The audio output device code the telephony voice TX path.
5818 */
5819 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5820 /** @hide
5821 * The audio output device code for an analog jack with line impedance detected.
5822 */
5823 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5824 /** @hide
5825 * The audio output device code for HDMI Audio Return Channel.
5826 */
5827 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5828 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005829 * The audio output device code for HDMI enhanced Audio Return Channel.
5830 */
5831 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5832 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005833 * The audio output device code for S/PDIF digital connection.
5834 */
5835 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5836 /** @hide
5837 * The audio output device code for built-in FM transmitter.
5838 */
5839 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5840 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005841 * The audio output device code for echo reference injection point.
5842 */
5843 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5844 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005845 * The audio output device code for a BLE audio headset.
5846 */
5847 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5848 /** @hide
5849 * The audio output device code for a BLE audio speaker.
5850 */
5851 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5852 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01005853 * The audio output device code for a BLE audio brodcast group.
5854 */
5855 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
5856 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005857 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005858 * used in the future in a set method to select whatever default device is chosen by the
5859 * platform-specific implementation.
5860 */
5861 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5862
Eric Laurent948d3272014-05-16 15:18:45 -07005863 /** @hide
5864 * The audio input device code for default built-in microphone
5865 */
5866 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5867 /** @hide
5868 * The audio input device code for a Bluetooth SCO headset
5869 */
5870 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5871 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5872 /** @hide
5873 * The audio input device code for wired headset microphone
5874 */
5875 public static final int DEVICE_IN_WIRED_HEADSET =
5876 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5877 /** @hide
5878 * The audio input device code for HDMI
5879 */
5880 public static final int DEVICE_IN_HDMI =
5881 AudioSystem.DEVICE_IN_HDMI;
5882 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005883 * The audio input device code for HDMI ARC
5884 */
5885 public static final int DEVICE_IN_HDMI_ARC =
5886 AudioSystem.DEVICE_IN_HDMI_ARC;
5887
5888 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005889 * The audio input device code for HDMI EARC
5890 */
5891 public static final int DEVICE_IN_HDMI_EARC =
5892 AudioSystem.DEVICE_IN_HDMI_EARC;
5893
5894 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005895 * The audio input device code for telephony voice RX path
5896 */
5897 public static final int DEVICE_IN_TELEPHONY_RX =
5898 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5899 /** @hide
5900 * The audio input device code for built-in microphone pointing to the back
5901 */
5902 public static final int DEVICE_IN_BACK_MIC =
5903 AudioSystem.DEVICE_IN_BACK_MIC;
5904 /** @hide
5905 * The audio input device code for analog from a docking station
5906 */
5907 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5908 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5909 /** @hide
5910 * The audio input device code for digital from a docking station
5911 */
5912 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5913 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5914 /** @hide
5915 * The audio input device code for a USB audio accessory. The accessory is in USB host
5916 * mode and the Android device in USB device mode
5917 */
5918 public static final int DEVICE_IN_USB_ACCESSORY =
5919 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5920 /** @hide
5921 * The audio input device code for a USB audio device. The device is in USB device
5922 * mode and the Android device in USB host mode
5923 */
5924 public static final int DEVICE_IN_USB_DEVICE =
5925 AudioSystem.DEVICE_IN_USB_DEVICE;
5926 /** @hide
5927 * The audio input device code for a FM radio tuner
5928 */
5929 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5930 /** @hide
5931 * The audio input device code for a TV tuner
5932 */
5933 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5934 /** @hide
5935 * The audio input device code for an analog jack with line impedance detected
5936 */
5937 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5938 /** @hide
5939 * The audio input device code for a S/PDIF digital connection
5940 */
5941 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005942 /** @hide
5943 * The audio input device code for audio loopback
5944 */
5945 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005946 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005947 * The audio input device code for an echo reference capture point.
5948 */
5949 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5950 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005951 * The audio input device code for a BLE audio headset.
5952 */
5953 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005954
5955 /**
5956 * Return true if the device code corresponds to an output device.
5957 * @hide
5958 */
5959 public static boolean isOutputDevice(int device)
5960 {
5961 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5962 }
5963
5964 /**
5965 * Return true if the device code corresponds to an input device.
5966 * @hide
5967 */
5968 public static boolean isInputDevice(int device)
5969 {
5970 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5971 }
5972
5973
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005974 /**
5975 * Return the enabled devices for the specified output stream type.
5976 *
5977 * @param streamType The stream type to query. One of
5978 * {@link #STREAM_VOICE_CALL},
5979 * {@link #STREAM_SYSTEM},
5980 * {@link #STREAM_RING},
5981 * {@link #STREAM_MUSIC},
5982 * {@link #STREAM_ALARM},
5983 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005984 * {@link #STREAM_DTMF},
5985 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005986 *
5987 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5988 * stream. Zero or more of
5989 * {@link #DEVICE_OUT_EARPIECE},
5990 * {@link #DEVICE_OUT_SPEAKER},
5991 * {@link #DEVICE_OUT_WIRED_HEADSET},
5992 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5993 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5994 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5995 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5996 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5997 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5998 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005999 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006000 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
6001 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07006002 * {@link #DEVICE_OUT_USB_ACCESSORY}.
6003 * {@link #DEVICE_OUT_USB_DEVICE}.
6004 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
6005 * {@link #DEVICE_OUT_TELEPHONY_TX}.
6006 * {@link #DEVICE_OUT_LINE}.
6007 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08006008 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07006009 * {@link #DEVICE_OUT_SPDIF}.
6010 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006011 * {@link #DEVICE_OUT_DEFAULT} is not used here.
6012 *
6013 * The implementation may support additional device codes beyond those listed, so
6014 * the application should ignore any bits which it does not recognize.
6015 * Note that the information may be imprecise when the implementation
6016 * cannot distinguish whether a particular device is enabled.
6017 *
Andy Hungb11e4c72021-04-13 19:31:00 -07006018 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
6019 * will have multi-bit device types.
6020 * Prefer to use {@link #getDevicesForAttributes()} instead,
6021 * noting that getDevicesForStream() has a few small discrepancies
6022 * for better volume handling.
6023 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006024 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006025 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07006026 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006027 public int getDevicesForStream(int streamType) {
6028 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07006029 case STREAM_VOICE_CALL:
6030 case STREAM_SYSTEM:
6031 case STREAM_RING:
6032 case STREAM_MUSIC:
6033 case STREAM_ALARM:
6034 case STREAM_NOTIFICATION:
6035 case STREAM_DTMF:
6036 case STREAM_ACCESSIBILITY:
6037 final IAudioService service = getService();
6038 try {
6039 return service.getDeviceMaskForStream(streamType);
6040 } catch (RemoteException e) {
6041 throw e.rethrowFromSystemServer();
6042 }
6043 default:
6044 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08006045 }
6046 }
6047
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08006048 /**
6049 * @hide
6050 * Get the audio devices that would be used for the routing of the given audio attributes.
6051 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6052 * @return an empty list if there was an issue with the request, a list of audio devices
6053 * otherwise (typically one device, except for duplicated paths).
6054 */
6055 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006056 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006057 Manifest.permission.MODIFY_AUDIO_ROUTING,
6058 Manifest.permission.QUERY_AUDIO_STATE
kholoud mohamed37839212021-03-15 16:49:06 +00006059 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08006060 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08006061 @NonNull AudioAttributes attributes) {
6062 Objects.requireNonNull(attributes);
6063 final IAudioService service = getService();
6064 try {
6065 return service.getDevicesForAttributes(attributes);
6066 } catch (RemoteException e) {
6067 throw e.rethrowFromSystemServer();
6068 }
6069 }
6070
Paul Wangebadb692022-12-15 20:40:19 +00006071 // Each listener corresponds to a unique callback stub because each listener can subscribe to
6072 // different AudioAttributes.
6073 private final ConcurrentHashMap<OnDevicesForAttributesChangedListener,
6074 IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub =
6075 new ConcurrentHashMap<>();
6076
6077 private static final class IDevicesForAttributesCallbackStub
6078 extends IDevicesForAttributesCallback.Stub {
6079 ListenerInfo<OnDevicesForAttributesChangedListener> mInfo;
6080
6081 IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener,
6082 @NonNull Executor executor) {
6083 mInfo = new ListenerInfo<>(listener, executor);
6084 }
6085
6086 public void register(boolean register, AudioAttributes attributes) {
6087 try {
6088 if (register) {
6089 getService().addOnDevicesForAttributesChangedListener(attributes, this);
6090 } else {
6091 getService().removeOnDevicesForAttributesChangedListener(this);
6092 }
6093 } catch (RemoteException e) {
6094 throw e.rethrowFromSystemServer();
6095 }
6096 }
6097
6098 @Override
6099 public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume,
6100 List<AudioDeviceAttributes> devices) {
6101 // forVolume is ignored. The case where it is `true` is not handled.
6102 mInfo.mExecutor.execute(() ->
6103 mInfo.mListener.onDevicesForAttributesChanged(
6104 attributes, devices));
6105 }
6106 }
6107
6108 /**
6109 * @hide
6110 * Interface to be notified of when routing changes for the registered audio attributes.
6111 */
6112 @SystemApi
6113 public interface OnDevicesForAttributesChangedListener {
6114 /**
6115 * Called on the listener to indicate that the audio devices for the given audio
6116 * attributes have changed.
6117 * @param attributes the {@link AudioAttributes} whose routing changed
6118 * @param devices a list of newly routed audio devices
6119 */
6120 void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
6121 @NonNull List<AudioDeviceAttributes> devices);
6122 }
6123
6124 /**
6125 * @hide
6126 * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}.
6127 * @param attributes the {@link AudioAttributes} to listen for routing changes
6128 * @param executor
6129 * @param listener
6130 */
6131 @SystemApi
6132 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006133 Manifest.permission.MODIFY_AUDIO_ROUTING,
6134 Manifest.permission.QUERY_AUDIO_STATE
Paul Wangebadb692022-12-15 20:40:19 +00006135 })
6136 public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
6137 @NonNull @CallbackExecutor Executor executor,
6138 @NonNull OnDevicesForAttributesChangedListener listener) {
6139 Objects.requireNonNull(attributes);
6140 Objects.requireNonNull(executor);
6141 Objects.requireNonNull(listener);
6142
6143 synchronized (mDevicesForAttributesListenerToStub) {
6144 IDevicesForAttributesCallbackStub callbackStub =
6145 mDevicesForAttributesListenerToStub.get(listener);
6146
6147 if (callbackStub == null) {
6148 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor);
6149 mDevicesForAttributesListenerToStub.put(listener, callbackStub);
6150 }
6151
6152 callbackStub.register(true, attributes);
6153 }
6154 }
6155
6156 /**
6157 * @hide
6158 * Removes a previously registered listener for being notified of routing changes for the given
6159 * {@link AudioAttributes}.
6160 * @param listener
6161 */
6162 @SystemApi
6163 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006164 Manifest.permission.MODIFY_AUDIO_ROUTING,
6165 Manifest.permission.QUERY_AUDIO_STATE
Paul Wangebadb692022-12-15 20:40:19 +00006166 })
6167 public void removeOnDevicesForAttributesChangedListener(
6168 @NonNull OnDevicesForAttributesChangedListener listener) {
6169 Objects.requireNonNull(listener);
6170
6171 synchronized (mDevicesForAttributesListenerToStub) {
6172 IDevicesForAttributesCallbackStub callbackStub =
6173 mDevicesForAttributesListenerToStub.get(listener);
6174 if (callbackStub != null) {
6175 callbackStub.register(false, null /* attributes */);
6176 }
6177
6178 mDevicesForAttributesListenerToStub.remove(listener);
6179 }
6180 }
6181
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006182 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01006183 * Get the audio devices that would be used for the routing of the given audio attributes.
6184 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
6185 * the specified {@link AudioAttributes}.
6186 * The audio routing can change if audio devices are physically connected or disconnected or
6187 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
6188 * @param attributes the {@link AudioAttributes} for which the routing is being queried
6189 * @return an empty list if there was an issue with the request, a list of
6190 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
6191 */
6192 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
6193 @NonNull AudioAttributes attributes) {
6194 final List<AudioDeviceAttributes> devicesForAttributes;
6195 try {
6196 Objects.requireNonNull(attributes);
6197 final IAudioService service = getService();
6198 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
6199 } catch (Exception e) {
6200 Log.i(TAG, "No audio devices available for specified attributes.");
6201 return Collections.emptyList();
6202 }
6203
6204 // Map from AudioDeviceAttributes to AudioDeviceInfo
6205 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
6206 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
6207 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
6208 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
6209 if (deviceForAttributes.getType() == deviceInfo.getType()
6210 && TextUtils.equals(deviceForAttributes.getAddress(),
6211 deviceInfo.getAddress())) {
6212 deviceInfosForAttributes.add(deviceInfo);
6213 }
6214 }
6215 }
6216 return Collections.unmodifiableList(deviceInfosForAttributes);
6217 }
6218
6219 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006220 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006221 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02006222 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
6223 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006224 */
6225 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
6226 /**
6227 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006228 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02006229 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006230 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006231 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006232 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
6233 /**
6234 * @hide
6235 * Volume behavior for an audio device where the volume is always set to provide no attenuation
6236 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006237 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006238 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006239 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006240 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
6241 /**
6242 * @hide
6243 * Volume behavior for an audio device where the volume is either set to muted, or to provide
6244 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02006245 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006246 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006247 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006248 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
6249 /**
6250 * @hide
6251 * Volume behavior for an audio device where no software attenuation is applied, and
6252 * the volume is kept synchronized between the host and the device itself through a
6253 * device-specific protocol such as BT AVRCP.
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006254 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006255 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006256 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
6257 /**
6258 * @hide
6259 * Volume behavior for an audio device where no software attenuation is applied, and
6260 * the volume is kept synchronized between the host and the device itself through a
6261 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
6262 * normal vs in phone call).
6263 * @see #setMode(int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006264 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006265 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006266 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
6267
Yan Han6f96eec2023-01-20 14:22:15 +01006268 /**
6269 * @hide
6270 * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
6271 * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have
6272 * no effect, or an unreliable effect.
Yan Han47556d82023-02-14 16:37:31 +01006273 *
6274 * {@link #DEVICE_VOLUME_BEHAVIOR_FULL} will be returned instead by
6275 * {@link #getDeviceVolumeBehavior} for target SDK versions before U.
6276 *
6277 * @see #RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY
Yan Han6f96eec2023-01-20 14:22:15 +01006278 */
6279 @SystemApi
6280 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
6281
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006282 /** @hide */
6283 @IntDef({
6284 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6285 DEVICE_VOLUME_BEHAVIOR_FULL,
6286 DEVICE_VOLUME_BEHAVIOR_FIXED,
6287 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6288 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
Yan Han6f96eec2023-01-20 14:22:15 +01006289 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006290 })
6291 @Retention(RetentionPolicy.SOURCE)
6292 public @interface DeviceVolumeBehavior {}
6293
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006294 /** @hide */
6295 @IntDef({
6296 DEVICE_VOLUME_BEHAVIOR_UNSET,
6297 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6298 DEVICE_VOLUME_BEHAVIOR_FULL,
6299 DEVICE_VOLUME_BEHAVIOR_FIXED,
6300 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6301 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
Yan Han6f96eec2023-01-20 14:22:15 +01006302 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00006303 })
6304 @Retention(RetentionPolicy.SOURCE)
6305 public @interface DeviceVolumeBehaviorState {}
6306
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006307 /**
Yan Han6f96eec2023-01-20 14:22:15 +01006308 * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}.
6309 * @hide
6310 */
6311 @IntDef({
6312 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6313 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
6314 })
6315 @Retention(RetentionPolicy.SOURCE)
6316 public @interface AbsoluteDeviceVolumeBehavior {}
6317
6318 /**
Yan Han47556d82023-02-14 16:37:31 +01006319 * Volume behaviors that can be set with {@link #setDeviceVolumeBehavior}.
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006320 * @hide
Yan Han47556d82023-02-14 16:37:31 +01006321 */
6322 @IntDef({
6323 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6324 DEVICE_VOLUME_BEHAVIOR_FULL,
6325 DEVICE_VOLUME_BEHAVIOR_FIXED,
6326 })
6327 @Retention(RetentionPolicy.SOURCE)
6328 public @interface SettableDeviceVolumeBehavior {}
6329
6330 /**
6331 * @hide
6332 * Throws IAE on a non-settable volume behavior value
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006333 * @param volumeBehavior behavior value to check
6334 */
Yan Han47556d82023-02-14 16:37:31 +01006335 public static void enforceSettableVolumeBehavior(int volumeBehavior) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006336 switch (volumeBehavior) {
6337 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
6338 case DEVICE_VOLUME_BEHAVIOR_FULL:
6339 case DEVICE_VOLUME_BEHAVIOR_FIXED:
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006340 return;
6341 default:
6342 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
6343 }
6344 }
6345
6346 /**
6347 * @hide
6348 * Sets the volume behavior for an audio output device.
Yan Han47556d82023-02-14 16:37:31 +01006349 *
6350 * @see SettableDeviceVolumeBehavior
Marvin Ramin5495cc92020-07-23 11:58:33 +02006351 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006352 * @param deviceVolumeBehavior one of the device behaviors
6353 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006354 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006355 @RequiresPermission(anyOf = {
6356 Manifest.permission.MODIFY_AUDIO_ROUTING,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006357 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006358 })
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006359 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
Yan Han47556d82023-02-14 16:37:31 +01006360 @SettableDeviceVolumeBehavior int deviceVolumeBehavior) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006361 // verify arguments (validity of device type is enforced in server)
6362 Objects.requireNonNull(device);
Yan Han47556d82023-02-14 16:37:31 +01006363 enforceSettableVolumeBehavior(deviceVolumeBehavior);
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006364 // communicate with service
6365 final IAudioService service = getService();
6366 try {
6367 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
6368 mApplicationContext.getOpPackageName());
6369 } catch (RemoteException e) {
6370 throw e.rethrowFromSystemServer();
6371 }
6372 }
6373
6374 /**
6375 * @hide
Yan Han6f96eec2023-01-20 14:22:15 +01006376 * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by
6377 * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned
6378 * in its place.
6379 */
6380 @ChangeId
6381 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
Yan Han31b10112023-02-13 17:25:46 +01006382 @Overridable
Yan Han6f96eec2023-01-20 14:22:15 +01006383 public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L;
6384
6385 /**
6386 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006387 * Returns the volume device behavior for the given audio device
6388 * @param device the audio device
6389 * @return the volume behavior for the device
6390 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02006391 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00006392 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006393 Manifest.permission.MODIFY_AUDIO_ROUTING,
6394 Manifest.permission.QUERY_AUDIO_STATE,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006395 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
kholoud mohamed37839212021-03-15 16:49:06 +00006396 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02006397 public @DeviceVolumeBehavior
6398 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006399 // verify arguments (validity of device type is enforced in server)
6400 Objects.requireNonNull(device);
6401 // communicate with service
6402 final IAudioService service = getService();
6403 try {
Yan Han6f96eec2023-01-20 14:22:15 +01006404 int behavior = service.getDeviceVolumeBehavior(device);
6405 if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)
6406 && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
6407 return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
6408 }
6409 return behavior;
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07006410 } catch (RemoteException e) {
6411 throw e.rethrowFromSystemServer();
6412 }
6413 }
6414
kholoud mohamed37839212021-03-15 16:49:06 +00006415 /**
6416 * @hide
6417 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
6418 */
6419 @TestApi
6420 @RequiresPermission(anyOf = {
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006421 Manifest.permission.MODIFY_AUDIO_ROUTING,
6422 Manifest.permission.QUERY_AUDIO_STATE,
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006423 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
kholoud mohamed37839212021-03-15 16:49:06 +00006424 })
6425 public boolean isFullVolumeDevice() {
6426 final AudioAttributes attributes = new AudioAttributes.Builder()
6427 .setUsage(AudioAttributes.USAGE_MEDIA)
6428 .build();
6429 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
6430 for (AudioDeviceAttributes device : devices) {
6431 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
6432 return true;
6433 }
6434 }
6435 return false;
6436 }
6437
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006438 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006439 * Indicate wired accessory connection state change.
6440 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
6441 * @param state new connection state: 1 connected, 0 disconnected
6442 * @param name device name
6443 * {@hide}
6444 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006445 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006446 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair7b72c392022-04-04 13:25:46 +02006447 public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
6448 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006449 setWiredDeviceConnectionState(attributes, state);
6450 }
6451
6452 /**
6453 * Indicate wired accessory connection state change and attributes.
6454 * @param state new connection state: 1 connected, 0 disconnected
6455 * @param attributes attributes of the connected device
6456 * {@hide}
6457 */
6458 @UnsupportedAppUsage
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006459 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006460 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07006461 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006462 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02006463 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07006464 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006465 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006466 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006467 }
6468 }
6469
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00006470 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006471 * Indicate wired accessory connection state change.
6472 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
6473 * @param connected true for connected, false for disconnected
6474 * {@hide}
6475 */
6476 @TestApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006477 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08006478 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
6479 boolean connected) {
6480 try {
6481 getService().setTestDeviceConnectionState(device, connected);
6482 } catch (RemoteException e) {
6483 throw e.rethrowFromSystemServer();
6484 }
6485 }
6486
6487 /**
wescande7c17ba0c2021-07-30 16:46:14 +02006488 * Indicate Bluetooth profile connection state change.
6489 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
6490 * <code>previousDevice</code>
6491 * This operation is asynchronous.
6492 *
6493 * @param newDevice Bluetooth device connected or null if there is no new devices
6494 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
6495 * devices
William Escandeac11d772022-01-25 18:01:15 +01006496 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006497 * {@hide}
6498 */
wescande7c17ba0c2021-07-30 16:46:14 +02006499 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006500 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
wescande7c17ba0c2021-07-30 16:46:14 +02006501 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01006502 @Nullable BluetoothDevice previousDevice,
6503 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006504 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08006505 try {
wescande7c17ba0c2021-07-30 16:46:14 +02006506 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006507 } catch (RemoteException e) {
6508 throw e.rethrowFromSystemServer();
6509 }
6510 }
6511
Jeff Sharkey098d5802012-04-26 17:30:34 -07006512 /** {@hide} */
6513 public IRingtonePlayer getRingtonePlayer() {
6514 try {
6515 return getService().getRingtonePlayer();
6516 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006517 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006518 }
6519 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006520
6521 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006522 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07006523 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
6524 * should use this value as a default, and offer the user the option to override it.
6525 * The low latency output stream is typically either the device's primary output stream,
6526 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006527 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006528 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006529 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
6530 "android.media.property.OUTPUT_SAMPLE_RATE";
6531
6532 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006533 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07006534 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
6535 * should use this value as a minimum, and offer the user the option to override it.
6536 * The low latency output stream is typically either the device's primary output stream,
6537 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07006538 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08006539 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006540 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
6541 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
6542
6543 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07006544 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
6545 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6546 */
6547 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6548 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6549
6550 /**
6551 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6552 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6553 */
6554 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6555 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6556
6557 /**
ragoa7cc59c2015-12-02 11:31:15 -08006558 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6559 * available and supported with the expected frequency range and level response.
6560 */
6561 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6562 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6563 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006564 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006565 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006566 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6567 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006568 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6569 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6570 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006571 * @return A string representing the associated value for that property key,
6572 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006573 */
6574 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006575 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6576 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6577 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6578 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6579 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6580 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006581 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006582 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6583 // not found.
6584 return String.valueOf(getContext().getResources().getBoolean(
6585 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006586 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006587 return String.valueOf(getContext().getResources().getBoolean(
6588 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006589 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6590 return String.valueOf(getContext().getResources().getBoolean(
6591 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006592 } else {
6593 // null or unknown key
6594 return null;
6595 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006596 }
6597
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006598 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006599 * @hide
6600 * Sets an additional audio output device delay in milliseconds.
6601 *
6602 * The additional output delay is a request to the output device to
6603 * delay audio presentation (generally with respect to video presentation for better
6604 * synchronization).
6605 * It may not be supported by all output devices,
6606 * and typically increases the audio latency by the amount of additional
6607 * audio delay requested.
6608 *
6609 * If additional audio delay is supported by an audio output device,
6610 * it is expected to be supported for all output streams (and configurations)
6611 * opened on that device.
6612 *
6613 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006614 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006615 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6616 * @return true if successful, false if the device does not support output device delay
6617 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6618 */
6619 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00006620 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Andy Hung97aa07f82020-01-17 14:05:06 -08006621 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006622 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006623 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006624 try {
6625 return getService().setAdditionalOutputDeviceDelay(
6626 new AudioDeviceAttributes(device), delayMillis);
6627 } catch (RemoteException e) {
6628 throw e.rethrowFromSystemServer();
6629 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006630 }
6631
6632 /**
6633 * @hide
6634 * Returns the current additional audio output device delay in milliseconds.
6635 *
6636 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6637 * @return the additional output device delay. This is a non-negative number.
6638 * {@code 0} is returned if unsupported.
6639 */
6640 @SystemApi
6641 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006642 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006643 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006644 try {
6645 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6646 } catch (RemoteException e) {
6647 throw e.rethrowFromSystemServer();
6648 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006649 }
6650
6651 /**
6652 * @hide
6653 * Returns the maximum additional audio output device delay in milliseconds.
6654 *
6655 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6656 * @return the maximum output device delay in milliseconds that can be set.
6657 * This is a non-negative number
6658 * representing the additional audio delay supported for the device.
6659 * {@code 0} is returned if unsupported.
6660 */
6661 @SystemApi
6662 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006663 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006664 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006665 try {
6666 return getService().getMaxAdditionalOutputDeviceDelay(
6667 new AudioDeviceAttributes(device));
6668 } catch (RemoteException e) {
6669 throw e.rethrowFromSystemServer();
6670 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006671 }
6672
6673 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006674 * Returns the estimated latency for the given stream type in milliseconds.
6675 *
6676 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6677 * a better solution.
6678 * @hide
6679 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006680 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006681 public int getOutputLatency(int streamType) {
6682 return AudioSystem.getOutputLatency(streamType);
6683 }
6684
John Spurlock3346a802014-05-20 16:25:37 -04006685 /**
6686 * Registers a global volume controller interface. Currently limited to SystemUI.
6687 *
6688 * @hide
6689 */
6690 public void setVolumeController(IVolumeController controller) {
6691 try {
6692 getService().setVolumeController(controller);
6693 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006694 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006695 }
6696 }
6697
6698 /**
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006699 * Returns the registered volume controller interface.
6700 *
6701 * @hide
6702 */
6703 @Nullable
6704 public IVolumeController getVolumeController() {
6705 try {
6706 return getService().getVolumeController();
6707 } catch (RemoteException e) {
6708 throw e.rethrowFromSystemServer();
6709 }
6710 }
6711
6712 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006713 * Notify audio manager about volume controller visibility changes.
6714 * Currently limited to SystemUI.
6715 *
6716 * @hide
6717 */
6718 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6719 try {
6720 getService().notifyVolumeControllerVisible(controller, visible);
6721 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006722 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006723 }
6724 }
6725
6726 /**
John Spurlock3346a802014-05-20 16:25:37 -04006727 * Only useful for volume controllers.
6728 * @hide
6729 */
John Spurlock3346a802014-05-20 16:25:37 -04006730 public boolean isStreamAffectedByRingerMode(int streamType) {
6731 try {
6732 return getService().isStreamAffectedByRingerMode(streamType);
6733 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006734 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006735 }
6736 }
6737
6738 /**
6739 * Only useful for volume controllers.
6740 * @hide
6741 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006742 public boolean isStreamAffectedByMute(int streamType) {
6743 try {
6744 return getService().isStreamAffectedByMute(streamType);
6745 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006746 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006747 }
6748 }
6749
6750 /**
6751 * Only useful for volume controllers.
6752 * @hide
6753 */
John Spurlock3346a802014-05-20 16:25:37 -04006754 public void disableSafeMediaVolume() {
6755 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006756 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006757 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006758 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006759 }
6760 }
Eric Laurenta198a292014-02-18 16:26:17 -08006761
6762 /**
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00006763 * @hide
6764 * Lower media volume to RS1
6765 */
6766 public void lowerVolumeToRs1() {
6767 try {
6768 getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName());
6769 } catch (RemoteException e) {
6770 throw e.rethrowFromSystemServer();
6771 }
6772 }
6773
6774 /**
6775 * @hide
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006776 * @return the RS2 value used for momentary exposure warnings
6777 */
6778 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006779 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006780 public float getRs2Value() {
6781 try {
6782 return getService().getRs2Value();
6783 } catch (RemoteException e) {
6784 throw e.rethrowFromSystemServer();
6785 }
6786 }
6787
6788 /**
6789 * @hide
6790 * Sets the RS2 value used for momentary exposure warnings
6791 */
6792 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006793 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006794 public void setRs2Value(float rs2Value) {
6795 try {
6796 getService().setRs2Value(rs2Value);
6797 } catch (RemoteException e) {
6798 throw e.rethrowFromSystemServer();
6799 }
6800 }
6801
6802 /**
6803 * @hide
6804 * @return the current computed sound dose value
6805 */
6806 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006807 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006808 public float getCsd() {
6809 try {
6810 return getService().getCsd();
6811 } catch (RemoteException e) {
6812 throw e.rethrowFromSystemServer();
6813 }
6814 }
6815
6816 /**
6817 * @hide
6818 * Sets the computed sound dose value to {@code csd}
6819 */
6820 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006821 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006822 public void setCsd(float csd) {
6823 try {
6824 getService().setCsd(csd);
6825 } catch (RemoteException e) {
6826 throw e.rethrowFromSystemServer();
6827 }
6828 }
6829
6830 /**
6831 * @hide
6832 * Forces the computation of MEL values (used for CSD) on framework level. This will have the
6833 * result of ignoring the MEL values computed on HAL level. Should only be used in testing
6834 * since this can affect the certification of a device with EN50332-3 regulation.
6835 */
6836 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006837 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006838 public void forceUseFrameworkMel(boolean useFrameworkMel) {
6839 try {
6840 getService().forceUseFrameworkMel(useFrameworkMel);
6841 } catch (RemoteException e) {
6842 throw e.rethrowFromSystemServer();
6843 }
6844 }
6845
6846 /**
6847 * @hide
6848 * Forces the computation of CSD on all output devices.
6849 */
6850 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006851 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006852 public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
6853 try {
6854 getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices);
6855 } catch (RemoteException e) {
6856 throw e.rethrowFromSystemServer();
6857 }
6858 }
6859
6860 /**
6861 * @hide
6862 * Returns whether CSD is enabled on this device.
6863 */
6864 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00006865 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Vlad Popa4e9d10b2023-01-13 12:03:48 +01006866 public boolean isCsdEnabled() {
6867 try {
6868 return getService().isCsdEnabled();
6869 } catch (RemoteException e) {
6870 throw e.rethrowFromSystemServer();
6871 }
6872 }
6873
6874 /**
6875 * @hide
Jean-Michel Trivia5321ff2022-12-14 22:11:38 +00006876 * Sound dose warning at every 100% of dose during integration window
6877 */
6878 public static final int CSD_WARNING_DOSE_REACHED_1X = 1;
6879 /**
6880 * @hide
6881 * Sound dose warning when 500% of dose is reached during integration window
6882 */
6883 public static final int CSD_WARNING_DOSE_REPEATED_5X = 2;
6884 /**
6885 * @hide
6886 * Sound dose warning after a momentary exposure event
6887 */
6888 public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3;
6889 /**
6890 * @hide
6891 * Sound dose warning at every 100% of dose during integration window
6892 */
6893 public static final int CSD_WARNING_ACCUMULATION_START = 4;
6894
6895 /** @hide */
6896 @IntDef(flag = false, value = {
6897 CSD_WARNING_DOSE_REACHED_1X,
6898 CSD_WARNING_DOSE_REPEATED_5X,
6899 CSD_WARNING_MOMENTARY_EXPOSURE,
6900 CSD_WARNING_ACCUMULATION_START }
6901 )
6902 @Retention(RetentionPolicy.SOURCE)
6903 public @interface CsdWarning {}
6904
6905 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006906 * Only useful for volume controllers.
6907 * @hide
6908 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006909 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006910 public void setRingerModeInternal(int ringerMode) {
6911 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006912 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006913 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006914 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006915 }
6916 }
6917
6918 /**
6919 * Only useful for volume controllers.
6920 * @hide
6921 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006922 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006923 public int getRingerModeInternal() {
6924 try {
6925 return getService().getRingerModeInternal();
6926 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006927 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006928 }
6929 }
6930
6931 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006932 * Only useful for volume controllers.
6933 * @hide
6934 */
6935 public void setVolumePolicy(VolumePolicy policy) {
6936 try {
6937 getService().setVolumePolicy(policy);
6938 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006939 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006940 }
6941 }
6942
6943 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006944 * Set Hdmi Cec system audio mode.
6945 *
6946 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006947 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006948 * @hide
6949 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006950 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006951 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006952 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006953 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006954 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006955 }
6956 }
6957
6958 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006959 * Returns true if Hdmi Cec system audio mode is supported.
6960 *
6961 * @hide
6962 */
6963 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006964 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006965 public boolean isHdmiSystemAudioSupported() {
6966 try {
6967 return getService().isHdmiSystemAudioSupported();
6968 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006969 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006970 }
6971 }
6972
6973 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006974 * Return codes for listAudioPorts(), createAudioPatch() ...
6975 */
6976
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006977 /** @hide */
6978 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006979 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006980 /**
6981 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006982 */
6983 public static final int ERROR = AudioSystem.ERROR;
6984 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006985 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006986 */
6987 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6988 /** @hide
6989 */
6990 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6991 /** @hide
6992 */
6993 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6994 /** @hide
6995 */
6996 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006997 /**
6998 * An error code indicating that the object reporting it is no longer valid and needs to
6999 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08007000 */
7001 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
7002
7003 /**
7004 * Returns a list of descriptors for all audio ports managed by the audio framework.
7005 * Audio ports are nodes in the audio framework or audio hardware that can be configured
7006 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
7007 * See AudioPort for a list of attributes of each audio port.
7008 * @param ports An AudioPort ArrayList where the list will be returned.
7009 * @hide
7010 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007011 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007012 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007013 return updateAudioPortCache(ports, null, null);
7014 }
7015
7016 /**
7017 * Returns a list of descriptors for all audio ports managed by the audio framework as
7018 * it was before the last update calback.
7019 * @param ports An AudioPort ArrayList where the list will be returned.
7020 * @hide
7021 */
7022 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
7023 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08007024 }
7025
7026 /**
7027 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
7028 * @see listAudioPorts(ArrayList<AudioPort>)
7029 * @hide
7030 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07007031 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007032 if (devices == null) {
7033 return ERROR_BAD_VALUE;
7034 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007035 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007036 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07007037 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007038 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07007039 }
7040 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08007041 }
7042
7043 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007044 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
7045 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
7046 * @hide
7047 */
7048 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
7049 if (devices == null) {
7050 return ERROR_BAD_VALUE;
7051 }
7052 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
7053 int status = updateAudioPortCache(null, null, ports);
7054 if (status == SUCCESS) {
7055 filterDevicePorts(ports, devices);
7056 }
7057 return status;
7058 }
7059
7060 private static void filterDevicePorts(ArrayList<AudioPort> ports,
7061 ArrayList<AudioDevicePort> devices) {
7062 devices.clear();
7063 for (int i = 0; i < ports.size(); i++) {
7064 if (ports.get(i) instanceof AudioDevicePort) {
7065 devices.add((AudioDevicePort)ports.get(i));
7066 }
7067 }
7068 }
7069
7070 /**
Eric Laurenta198a292014-02-18 16:26:17 -08007071 * Create a connection between two or more devices. The framework will reject the request if
7072 * device types are not compatible or the implementation does not support the requested
7073 * configuration.
7074 * NOTE: current implementation is limited to one source and one sink per patch.
7075 * @param patch AudioPatch array where the newly created patch will be returned.
7076 * As input, if patch[0] is not null, the specified patch will be replaced by the
7077 * new patch created. This avoids calling releaseAudioPatch() when modifying a
7078 * patch and allows the implementation to optimize transitions.
7079 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
7080 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
7081 *
7082 * @return - {@link #SUCCESS} if connection is successful.
7083 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
7084 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
7085 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
7086 * a patch.
7087 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7088 * - {@link #ERROR} if patch cannot be connected for any other reason.
7089 *
7090 * patch[0] contains the newly created patch
7091 * @hide
7092 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007093 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007094 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08007095 AudioPortConfig[] sources,
7096 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007097 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08007098 }
7099
7100 /**
7101 * Releases an existing audio patch connection.
7102 * @param patch The audio patch to disconnect.
7103 * @return - {@link #SUCCESS} if disconnection is successful.
7104 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
7105 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
7106 * a patch.
7107 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7108 * - {@link #ERROR} if patch cannot be released for any other reason.
7109 * @hide
7110 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007111 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007112 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007113 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08007114 }
7115
7116 /**
7117 * List all existing connections between audio ports.
7118 * @param patches An AudioPatch array where the list will be returned.
7119 * @hide
7120 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007121 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07007122 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007123 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08007124 }
7125
7126 /**
7127 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
7128 * AudioGain.buildConfig()
7129 * @hide
7130 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07007131 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07007132 if (port == null || gain == null) {
7133 return ERROR_BAD_VALUE;
7134 }
7135 AudioPortConfig activeConfig = port.activeConfig();
7136 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
7137 activeConfig.channelMask(), activeConfig.format(), gain);
7138 config.mConfigMask = AudioPortConfig.GAIN;
7139 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08007140 }
7141
7142 /**
7143 * Listener registered by client to be notified upon new audio port connections,
7144 * disconnections or attributes update.
7145 * @hide
7146 */
7147 public interface OnAudioPortUpdateListener {
7148 /**
7149 * Callback method called upon audio port list update.
7150 * @param portList the updated list of audio ports
7151 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007152 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08007153
7154 /**
7155 * Callback method called upon audio patch list update.
7156 * @param patchList the updated list of audio patches
7157 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007158 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08007159
7160 /**
7161 * Callback method called when the mediaserver dies
7162 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07007163 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08007164 }
7165
7166 /**
Eric Laurent700e7342014-05-02 18:33:15 -07007167 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08007168 * @hide
7169 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007170 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08007171 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007172 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08007173 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08007174 }
7175
7176 /**
Eric Laurent700e7342014-05-02 18:33:15 -07007177 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08007178 * @hide
7179 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01007180 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08007181 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08007182 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08007183 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007184
7185 //
7186 // AudioPort implementation
7187 //
7188
Cole Faust7da659b2022-10-15 21:33:29 -07007189 private static final int AUDIOPORT_GENERATION_INIT = 0;
7190 private static Object sAudioPortGenerationLock = new Object();
7191 @GuardedBy("sAudioPortGenerationLock")
7192 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
7193 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
7194 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
7195 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07007196
Eric Laurentf076db42015-01-14 13:23:27 -08007197 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07007198 int generation;
Cole Faust7da659b2022-10-15 21:33:29 -07007199 synchronized (sAudioPortGenerationLock) {
Eric Laurentf076db42015-01-14 13:23:27 -08007200 generation = sAudioPortGeneration;
7201 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07007202 }
7203 return generation;
7204 }
7205
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007206 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
7207 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007208 sAudioPortEventHandler.init();
Cole Faust7da659b2022-10-15 21:33:29 -07007209 synchronized (sAudioPortGenerationLock) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007210
Eric Laurentf076db42015-01-14 13:23:27 -08007211 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007212 int[] patchGeneration = new int[1];
7213 int[] portGeneration = new int[1];
7214 int status;
7215 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
7216 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
7217
7218 do {
7219 newPorts.clear();
7220 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07007221 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09007222 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07007223 return status;
7224 }
7225 newPatches.clear();
7226 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07007227 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09007228 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07007229 return status;
7230 }
jiabinc4ecaa52017-09-26 14:28:41 -07007231 // Loop until patch generation is the same as port generation unless audio ports
7232 // and audio patches are not null.
7233 } while (patchGeneration[0] != portGeneration[0]
7234 && (ports == null || patches == null));
7235 // If the patch generation doesn't equal port generation, return ERROR here in case
7236 // of mismatch between audio ports and audio patches.
7237 if (patchGeneration[0] != portGeneration[0]) {
7238 return ERROR;
7239 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007240
7241 for (int i = 0; i < newPatches.size(); i++) {
7242 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07007243 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
7244 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07007245 newPatches.get(i).sources()[j] = portCfg;
7246 }
7247 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07007248 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
7249 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07007250 newPatches.get(i).sinks()[j] = portCfg;
7251 }
7252 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09007253 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
7254 AudioPatch newPatch = i.next();
7255 boolean hasInvalidPort = false;
7256 for (AudioPortConfig portCfg : newPatch.sources()) {
7257 if (portCfg == null) {
7258 hasInvalidPort = true;
7259 break;
7260 }
7261 }
7262 for (AudioPortConfig portCfg : newPatch.sinks()) {
7263 if (portCfg == null) {
7264 hasInvalidPort = true;
7265 break;
7266 }
7267 }
7268 if (hasInvalidPort) {
7269 // Temporarily remove patches with invalid ports. One who created the patch
7270 // is responsible for dealing with the port change.
7271 i.remove();
7272 }
7273 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007274
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007275 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08007276 sAudioPortsCached = newPorts;
7277 sAudioPatchesCached = newPatches;
7278 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07007279 }
7280 if (ports != null) {
7281 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08007282 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07007283 }
7284 if (patches != null) {
7285 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08007286 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07007287 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07007288 if (previousPorts != null) {
7289 previousPorts.clear();
7290 previousPorts.addAll(sPreviousAudioPortsCached);
7291 }
Eric Laurentb69681c2014-05-19 19:02:51 -07007292 }
7293 return SUCCESS;
7294 }
7295
Eric Laurentf076db42015-01-14 13:23:27 -08007296 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007297 AudioPort port = portCfg.port();
7298 int k;
7299 for (k = 0; k < ports.size(); k++) {
7300 // compare handles because the port returned by JNI is not of the correct
7301 // subclass
7302 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07007303 port = ports.get(k);
7304 break;
7305 }
7306 }
7307 if (k == ports.size()) {
Darwin Huangbb111732022-10-21 13:14:32 +00007308 // This can happen in case of stale audio patch referring to a removed device and is
7309 // handled by the caller.
Eric Laurentb69681c2014-05-19 19:02:51 -07007310 return null;
7311 }
7312 AudioGainConfig gainCfg = portCfg.gain();
7313 if (gainCfg != null) {
7314 AudioGain gain = port.gain(gainCfg.index());
7315 gainCfg = gain.buildConfig(gainCfg.mode(),
7316 gainCfg.channelMask(),
7317 gainCfg.values(),
7318 gainCfg.rampDurationMs());
7319 }
7320 return port.buildConfig(portCfg.samplingRate(),
7321 portCfg.channelMask(),
7322 portCfg.format(),
7323 gainCfg);
7324 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007325
7326 private OnAmPortUpdateListener mPortListener = null;
7327
7328 /**
7329 * The message sent to apps when the contents of the device list changes if they provide
Paul Wang9b2d0482022-05-17 10:18:01 +00007330 * a {@link Handler} object to {@link registerAudioDeviceCallback}.
Paul McLeane3383cc2015-05-08 11:41:20 -07007331 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07007332 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
7333 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
7334 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07007335
Paul McLean8e6c9f42015-05-19 11:13:41 -07007336 /**
7337 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
7338 */
Jack He89f97982018-05-02 19:10:56 -07007339 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07007340 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07007341
7342 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007343 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
7344 * the results list to only those device types they are interested in.
7345 */
7346 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07007347 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7348 * source (i.e. input) audio devices.
7349 */
7350 public static final int GET_DEVICES_INPUTS = 0x0001;
7351
7352 /**
7353 * Specifies to the {@link AudioManager#getDevices(int)} method to include
7354 * sink (i.e. output) audio devices.
7355 */
7356 public static final int GET_DEVICES_OUTPUTS = 0x0002;
7357
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007358 /** @hide */
7359 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
7360 GET_DEVICES_INPUTS,
7361 GET_DEVICES_OUTPUTS }
7362 )
7363 @Retention(RetentionPolicy.SOURCE)
7364 public @interface AudioDeviceRole {}
7365
Paul McLeane3383cc2015-05-08 11:41:20 -07007366 /**
7367 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
7368 * source and sink devices.
7369 */
7370 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
7371
7372 /**
7373 * Determines if a given AudioDevicePort meets the specified filter criteria.
7374 * @param port The port to test.
7375 * @param flags A set of bitflags specifying the criteria to test.
7376 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
7377 **/
7378 private static boolean checkFlags(AudioDevicePort port, int flags) {
7379 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
7380 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
7381 }
7382
Paul McLean11354572015-08-07 12:50:48 -06007383 private static boolean checkTypes(AudioDevicePort port) {
7384 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07007385 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06007386 }
7387
Paul McLeane3383cc2015-05-08 11:41:20 -07007388 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007389 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
7390 * currently connected to the system and meeting the criteria specified in the
7391 * <code>flags</code> parameter.
jiabin83221092023-01-10 00:15:47 +00007392 * Notes that Android audio framework only support one device per device type. In that case,
7393 * if there are multiple audio device with the same device type connected to the Android device,
7394 * only the last reported device will be known by Android audio framework and returned by this
7395 * API.
Paul McLeane3383cc2015-05-08 11:41:20 -07007396 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007397 * @see #GET_DEVICES_OUTPUTS
7398 * @see #GET_DEVICES_INPUTS
7399 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07007400 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7401 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07007402 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007403 return getDevicesStatic(flags);
7404 }
7405
Paul McLean8e6c9f42015-05-19 11:13:41 -07007406 /**
7407 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
7408 * objects from the current (internal) AudioDevicePort list.
7409 */
Paul McLean03346882015-05-12 15:36:56 -07007410 private static AudioDeviceInfo[]
7411 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007412
Paul McLean8e6c9f42015-05-19 11:13:41 -07007413 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07007414 int numRecs = 0;
7415 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007416 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007417 numRecs++;
7418 }
7419 }
7420
Paul McLean8e6c9f42015-05-19 11:13:41 -07007421 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07007422 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
7423 int slot = 0;
7424 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06007425 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07007426 deviceList[slot++] = new AudioDeviceInfo(port);
7427 }
7428 }
7429
7430 return deviceList;
7431 }
7432
Paul McLean03346882015-05-12 15:36:56 -07007433 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07007434 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
7435 * the add/remove callback mechanism to provide a list of the newly added or removed devices
7436 * rather than the whole list and make the app figure it out.
7437 * Note that calling this method with:
7438 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
7439 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07007440 */
7441 private static AudioDeviceInfo[] calcListDeltas(
7442 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
7443
7444 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
7445
7446 AudioDevicePort cur_port = null;
7447 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
7448 boolean cur_port_found = false;
7449 cur_port = ports_B.get(cur_index);
7450 for (int prev_index = 0;
7451 prev_index < ports_A.size() && !cur_port_found;
7452 prev_index++) {
7453 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
7454 }
7455
7456 if (!cur_port_found) {
7457 delta_ports.add(cur_port);
7458 }
7459 }
7460
7461 return infoListFromPortList(delta_ports, flags);
7462 }
7463
Paul McLeane3383cc2015-05-08 11:41:20 -07007464 /**
Paul McLean03346882015-05-12 15:36:56 -07007465 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
7466 * connected to the system and meeting the criteria specified in the <code>flags</code>
7467 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007468 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07007469 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08007470 * @see #GET_DEVICES_OUTPUTS
7471 * @see #GET_DEVICES_INPUTS
7472 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07007473 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7474 * @hide
7475 */
7476 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
7477 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
7478 int status = AudioManager.listAudioDevicePorts(ports);
7479 if (status != AudioManager.SUCCESS) {
7480 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07007481 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07007482 }
7483
7484 return infoListFromPortList(ports, flags);
7485 }
7486
7487 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007488 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
7489 * @param portId The audio port ID to look up for.
7490 * @param flags A set of bitflags specifying the criteria to test.
7491 * @see #GET_DEVICES_OUTPUTS
7492 * @see #GET_DEVICES_INPUTS
7493 * @see #GET_DEVICES_ALL
7494 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
7495 * @hide
7496 */
7497 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
7498 if (portId == 0) {
7499 return null;
7500 }
7501 AudioDeviceInfo[] devices = getDevicesStatic(flags);
7502 for (AudioDeviceInfo device : devices) {
7503 if (device.getId() == portId) {
7504 return device;
7505 }
7506 }
7507 return null;
7508 }
7509
7510 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007511 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07007512 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007513 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
7514 * notifications.
7515 * @param handler Specifies the {@link Handler} object for the thread on which to execute
7516 * the callback. If <code>null</code>, the {@link Handler} associated with the main
7517 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07007518 */
Paul McLean03346882015-05-12 15:36:56 -07007519 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08007520 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07007521 synchronized (mDeviceCallbacks) {
7522 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07007523 if (mDeviceCallbacks.size() == 0) {
7524 if (mPortListener == null) {
7525 mPortListener = new OnAmPortUpdateListener();
7526 }
7527 registerAudioPortUpdateListener(mPortListener);
7528 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007529 NativeEventHandlerDelegate delegate =
7530 new NativeEventHandlerDelegate(callback, handler);
7531 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07007532 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07007533 }
7534 }
7535 }
7536
7537 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007538 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07007539 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007540 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08007541 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07007542 */
Paul McLean03346882015-05-12 15:36:56 -07007543 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
7544 synchronized (mDeviceCallbacks) {
7545 if (mDeviceCallbacks.containsKey(callback)) {
7546 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07007547 if (mDeviceCallbacks.size() == 0) {
7548 unregisterAudioPortUpdateListener(mPortListener);
7549 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007550 }
7551 }
7552 }
7553
jiabinc0f49442018-01-05 10:23:50 -08007554 /**
7555 * Set port id for microphones by matching device type and address.
7556 * @hide
7557 */
7558 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
7559 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
7560 for (int i = microphones.size() - 1; i >= 0; i--) {
7561 boolean foundPortId = false;
7562 for (AudioDeviceInfo device : devices) {
7563 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
7564 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
7565 microphones.get(i).setId(device.getId());
7566 foundPortId = true;
7567 break;
7568 }
7569 }
7570 if (!foundPortId) {
7571 Log.i(TAG, "Failed to find port id for device with type:"
7572 + microphones.get(i).getType() + " address:"
7573 + microphones.get(i).getAddress());
7574 microphones.remove(i);
7575 }
7576 }
7577 }
7578
7579 /**
jiabin589a2362018-02-22 16:21:53 -08007580 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
7581 * @hide
7582 */
7583 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
7584 int deviceType = deviceInfo.getType();
7585 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
7586 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
7587 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
7588 : MicrophoneInfo.LOCATION_PERIPHERAL;
7589 MicrophoneInfo microphone = new MicrophoneInfo(
7590 deviceInfo.getPort().name() + deviceInfo.getId(),
7591 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
7592 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
7593 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
7594 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
7595 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
7596 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
7597 microphone.setId(deviceInfo.getId());
7598 return microphone;
7599 }
7600
7601 /**
jiabind0be5b22018-04-10 14:10:04 -07007602 * Add {@link MicrophoneInfo} by device information while filtering certain types.
7603 */
7604 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
7605 HashSet<Integer> filterTypes) {
7606 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
7607 for (AudioDeviceInfo device : devices) {
7608 if (filterTypes.contains(device.getType())) {
7609 continue;
7610 }
7611 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
7612 microphones.add(microphone);
7613 }
7614 }
7615
7616 /**
jiabinc0f49442018-01-05 10:23:50 -08007617 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
7618 * of all available microphones. The list is empty when no microphones are available
7619 * on the device. An error during the query will result in an IOException being thrown.
7620 *
7621 * @return a list that contains all microphones' characteristics
7622 * @throws IOException if an error occurs.
7623 */
7624 public List<MicrophoneInfo> getMicrophones() throws IOException {
7625 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
7626 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07007627 HashSet<Integer> filterTypes = new HashSet<>();
7628 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08007629 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07007630 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07007631 if (status != AudioManager.ERROR_INVALID_OPERATION) {
7632 Log.e(TAG, "getMicrophones failed:" + status);
7633 }
7634 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07007635 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
7636 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08007637 }
7638 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07007639 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
7640 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08007641 return microphones;
7642 }
7643
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007644 /**
7645 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01007646 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007647 *
7648 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01007649 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007650 * @hide
7651 */
William Escandea05cb452021-12-08 14:14:19 +01007652 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7653 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
7654 ArrayList<Integer> formatsList = new ArrayList<>();
7655 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007656
William Escandea05cb452021-12-08 14:14:19 +01007657 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
7658 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007659 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01007660 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
7661 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007662 }
7663
William Escandea05cb452021-12-08 14:14:19 +01007664 for (Integer format : formatsList) {
7665 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
7666 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
Etienne Ruffieux2c5180a2022-03-08 13:31:41 +00007667 codecConfigList.add(
7668 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007669 }
William Escandea05cb452021-12-08 14:14:19 +01007670 }
7671 return codecConfigList;
7672 }
7673
Patty Huang1dc21e12022-07-06 00:12:03 +08007674 private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
7675 @AudioSystem.BtOffloadDeviceType int deviceType) {
William Escandea05cb452021-12-08 14:14:19 +01007676 ArrayList<Integer> formatsList = new ArrayList<>();
7677 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
7678
7679 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
Patty Huang1dc21e12022-07-06 00:12:03 +08007680 deviceType, formatsList);
William Escandea05cb452021-12-08 14:14:19 +01007681 if (status != AudioManager.SUCCESS) {
7682 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08007683 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007684 }
William Escandea05cb452021-12-08 14:14:19 +01007685
7686 for (Integer format : formatsList) {
7687 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
7688 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
7689 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
7690 .setCodecType(btLeAudioCodec)
7691 .build());
7692 }
7693 }
7694 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007695 }
7696
Patty Huang1dc21e12022-07-06 00:12:03 +08007697 /**
7698 * Returns a list of audio formats that corresponds to encoding formats
7699 * supported on offload path for Le audio playback.
7700 *
7701 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
7702 * supported for offload Le Audio playback
7703 * @hide
7704 */
7705 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7706 @NonNull
7707 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
7708 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
7709 }
7710
7711 /**
7712 * Returns a list of audio formats that corresponds to encoding formats
7713 * supported on offload path for Le Broadcast playback.
7714 *
7715 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
7716 * supported for offload Le Broadcast playback
7717 * @hide
7718 */
7719 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7720 @NonNull
7721 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
7722 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
7723 }
7724
Paul McLeancbeb8a22015-06-10 08:21:27 -07007725 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
7726 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
7727 // of the ports that exist at the time of the last notification.
7728 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
7729
Paul McLeane3383cc2015-05-08 11:41:20 -07007730 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007731 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07007732 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07007733 */
jiabin8c3a7672018-05-22 15:44:21 -07007734 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07007735 int status;
7736
Paul McLeancbeb8a22015-06-10 08:21:27 -07007737 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07007738 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
7739 status = AudioManager.listAudioDevicePorts(current_ports);
7740 if (status != AudioManager.SUCCESS) {
7741 return;
7742 }
7743
Paul McLeancbeb8a22015-06-10 08:21:27 -07007744 if (handler != null) {
7745 // This is the callback for the registration, so send the current list
7746 AudioDeviceInfo[] deviceList =
7747 infoListFromPortList(current_ports, GET_DEVICES_ALL);
7748 handler.sendMessage(
7749 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
7750 } else {
7751 AudioDeviceInfo[] added_devices =
7752 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
7753 AudioDeviceInfo[] removed_devices =
7754 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07007755 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07007756 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
7757 handler = mDeviceCallbacks.valueAt(i).getHandler();
7758 if (handler != null) {
7759 if (removed_devices.length != 0) {
7760 handler.sendMessage(Message.obtain(handler,
7761 MSG_DEVICES_DEVICES_REMOVED,
7762 removed_devices));
7763 }
7764 if (added_devices.length != 0) {
7765 handler.sendMessage(Message.obtain(handler,
7766 MSG_DEVICES_DEVICES_ADDED,
7767 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07007768 }
Paul McLean03346882015-05-12 15:36:56 -07007769 }
7770 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007771 }
7772 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007773
7774 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07007775 }
7776
7777 /**
7778 * Handles Port list update notifications from the AudioManager
7779 */
7780 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
7781 static final String TAG = "OnAmPortUpdateListener";
7782 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07007783 synchronized (mDeviceCallbacks) {
7784 broadcastDeviceListChange_sync(null);
7785 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007786 }
7787
7788 /**
7789 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007790 * Note: We don't do anything with Patches at this time, so ignore this notification.
7791 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07007792 */
7793 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
7794
7795 /**
7796 * Callback method called when the mediaserver dies
7797 */
7798 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07007799 synchronized (mDeviceCallbacks) {
7800 broadcastDeviceListChange_sync(null);
7801 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007802 }
7803 }
7804
Eric Laurent1d3cdce2018-01-20 10:31:21 -08007805
7806 /**
7807 * @hide
7808 * Abstract class to receive event notification about audioserver process state.
7809 */
7810 @SystemApi
7811 public abstract static class AudioServerStateCallback {
7812 public void onAudioServerDown() { }
7813 public void onAudioServerUp() { }
7814 }
7815
7816 private Executor mAudioServerStateExec;
7817 private AudioServerStateCallback mAudioServerStateCb;
7818 private final Object mAudioServerStateCbLock = new Object();
7819
7820 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
7821 new IAudioServerStateDispatcher.Stub() {
7822 @Override
7823 public void dispatchAudioServerStateChange(boolean state) {
7824 Executor exec;
7825 AudioServerStateCallback cb;
7826
7827 synchronized (mAudioServerStateCbLock) {
7828 exec = mAudioServerStateExec;
7829 cb = mAudioServerStateCb;
7830 }
7831
7832 if ((exec == null) || (cb == null)) {
7833 return;
7834 }
7835 if (state) {
7836 exec.execute(() -> cb.onAudioServerUp());
7837 } else {
7838 exec.execute(() -> cb.onAudioServerDown());
7839 }
7840 }
7841 };
7842
7843 /**
7844 * @hide
7845 * Registers a callback for notification of audio server state changes.
7846 * @param executor {@link Executor} to handle the callbacks
7847 * @param stateCallback the callback to receive the audio server state changes
7848 * To remove the callabck, pass a null reference for both executor and stateCallback.
7849 */
7850 @SystemApi
7851 public void setAudioServerStateCallback(@NonNull Executor executor,
7852 @NonNull AudioServerStateCallback stateCallback) {
7853 if (stateCallback == null) {
7854 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
7855 }
7856 if (executor == null) {
7857 throw new IllegalArgumentException(
7858 "Illegal null Executor for the AudioServerStateCallback");
7859 }
7860
7861 synchronized (mAudioServerStateCbLock) {
7862 if (mAudioServerStateCb != null) {
7863 throw new IllegalStateException(
7864 "setAudioServerStateCallback called with already registered callabck");
7865 }
7866 final IAudioService service = getService();
7867 try {
7868 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7869 } catch (RemoteException e) {
7870 throw e.rethrowFromSystemServer();
7871 }
7872 mAudioServerStateExec = executor;
7873 mAudioServerStateCb = stateCallback;
7874 }
7875 }
7876
7877 /**
7878 * @hide
7879 * Unregisters the callback for notification of audio server state changes.
7880 */
7881 @SystemApi
7882 public void clearAudioServerStateCallback() {
7883 synchronized (mAudioServerStateCbLock) {
7884 if (mAudioServerStateCb != null) {
7885 final IAudioService service = getService();
7886 try {
7887 service.unregisterAudioServerStateDispatcher(
7888 mAudioServerStateDispatcher);
7889 } catch (RemoteException e) {
7890 throw e.rethrowFromSystemServer();
7891 }
7892 }
7893 mAudioServerStateExec = null;
7894 mAudioServerStateCb = null;
7895 }
7896 }
7897
7898 /**
7899 * @hide
7900 * Checks if native audioservice is running or not.
7901 * @return true if native audioservice runs, false otherwise.
7902 */
7903 @SystemApi
7904 public boolean isAudioServerRunning() {
7905 final IAudioService service = getService();
7906 try {
7907 return service.isAudioServerRunning();
7908 } catch (RemoteException e) {
7909 throw e.rethrowFromSystemServer();
7910 }
7911 }
7912
jiabin39940752018-04-02 18:18:45 -07007913 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007914 * Sets the surround sound mode.
7915 *
7916 * @return true if successful, otherwise false
7917 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00007918 @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
Kriti Dang527e66c2021-03-04 10:37:22 +01007919 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7920 try {
7921 return getService().setEncodedSurroundMode(mode);
7922 } catch (RemoteException e) {
7923 throw e.rethrowFromSystemServer();
7924 }
7925 }
7926
7927 /**
7928 * Gets the surround sound mode.
7929 *
7930 * @return true if successful, otherwise false
7931 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007932 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7933 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007934 return getService().getEncodedSurroundMode(
7935 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007936 } catch (RemoteException e) {
7937 throw e.rethrowFromSystemServer();
7938 }
7939 }
7940
7941 /**
jiabin39940752018-04-02 18:18:45 -07007942 * @hide
7943 * Returns all surround formats.
7944 * @return a map where the key is a surround format and
7945 * the value indicates the surround format is enabled or not
7946 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007947 @TestApi
7948 @NonNull
jiabin39940752018-04-02 18:18:45 -07007949 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007950 try {
7951 return getService().getSurroundFormats();
7952 } catch (RemoteException e) {
7953 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007954 }
jiabin39940752018-04-02 18:18:45 -07007955 }
7956
7957 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007958 * Sets and persists a certain surround format as enabled or not.
7959 * <p>
7960 * This API is called by TvSettings surround sound menu when user enables or disables a
7961 * surround sound format. This setting is persisted as global user setting.
7962 * Applications should revert their changes to surround sound settings unless they intend to
7963 * modify the global user settings across all apps. The framework does not auto-revert an
7964 * application's settings after a lifecycle event. Audio focus is not required to apply these
7965 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007966 *
jiabin39940752018-04-02 18:18:45 -07007967 * @param enabled the required surround format state, true for enabled, false for disabled
7968 * @return true if successful, otherwise false
7969 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00007970 @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007971 public boolean setSurroundFormatEnabled(
7972 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007973 try {
7974 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7975 } catch (RemoteException e) {
7976 throw e.rethrowFromSystemServer();
7977 }
7978 }
7979
7980 /**
7981 * Gets whether a certain surround format is enabled or not.
7982 * @param audioFormat a surround format
7983 *
7984 * @return whether the required surround format is enabled
7985 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007986 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7987 try {
7988 return getService().isSurroundFormatEnabled(audioFormat);
7989 } catch (RemoteException e) {
7990 throw e.rethrowFromSystemServer();
7991 }
jiabin39940752018-04-02 18:18:45 -07007992 }
7993
7994 /**
7995 * @hide
7996 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007997 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007998 *
Kriti Dang01924232021-03-02 13:51:09 +01007999 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07008000 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02008001 @TestApi
8002 @NonNull
8003 public List<Integer> getReportedSurroundFormats() {
8004 try {
8005 return getService().getReportedSurroundFormats();
8006 } catch (RemoteException e) {
8007 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07008008 }
jiabin39940752018-04-02 18:18:45 -07008009 }
8010
jiabin66f9e722018-11-02 16:20:19 -07008011 /**
8012 * Return if audio haptic coupled playback is supported or not.
8013 *
8014 * @return whether audio haptic playback supported.
8015 */
8016 public static boolean isHapticPlaybackSupported() {
8017 return AudioSystem.isHapticPlaybackSupported();
8018 }
8019
François Gaffie0699fec2018-07-09 14:35:10 +02008020 /**
8021 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08008022 * Indicates whether a platform supports the Ultrasound feature which covers the playback
8023 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
8024 * usage will be
8025 * To start the Ultrasound playback:
8026 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
8027 * To start the Ultrasound capture:
8028 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
8029 *
8030 * @return whether the ultrasound feature is supported, true when platform supports both
8031 * Ultrasound playback and capture, false otherwise.
8032 */
8033 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008034 @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND)
Carter Hsu3ea30de42022-02-15 15:59:00 +08008035 public boolean isUltrasoundSupported() {
8036 try {
8037 return getService().isUltrasoundSupported();
8038 } catch (RemoteException e) {
8039 throw e.rethrowFromSystemServer();
8040 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08008041 }
8042
8043 /**
8044 * @hide
Atneya Naireeab0a72022-12-15 09:32:51 -08008045 * Indicates whether the platform supports capturing content from the hotword recognition
8046 * pipeline. To capture content of this type, create an AudioRecord with
8047 * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}.
8048 * @param lookbackAudio Query if the hotword stream additionally supports providing buffered
8049 * audio prior to stream open.
8050 * @return True if the platform supports capturing hotword content, and if lookbackAudio
8051 * is true, if it additionally supports capturing buffered hotword content prior to stream
8052 * open. False otherwise.
8053 */
8054 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008055 @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
Atneya Naireeab0a72022-12-15 09:32:51 -08008056 public boolean isHotwordStreamSupported(boolean lookbackAudio) {
8057 try {
8058 return getService().isHotwordStreamSupported(lookbackAudio);
8059 } catch (RemoteException e) {
8060 return false;
8061 }
8062 }
8063
8064 /**
8065 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02008066 * Introspection API to retrieve audio product strategies.
8067 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
8068 * audio product strategies, which is indexed by a weakly typed index in order to be extended
8069 * by OEM without any needs of AOSP patches.
8070 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
8071 * strategy refered either by its index or human readable string. It will allow clients
8072 * application to start streaming data using these {@link AudioAttributes} on the selected
8073 * device by Audio Policy Engine.
8074 * @return a (possibly zero-length) array of
8075 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
8076 */
8077 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07008078 @NonNull
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008079 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07008080 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02008081 final IAudioService service = getService();
8082 try {
8083 return service.getAudioProductStrategies();
8084 } catch (RemoteException e) {
8085 throw e.rethrowFromSystemServer();
8086 }
8087 }
8088
François Gaffieadcd00a2018-09-18 17:06:26 +02008089 /**
8090 * @hide
8091 * Introspection API to retrieve audio volume groups.
8092 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
8093 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008094 * @return a (possibly zero-length) List of
8095 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02008096 */
8097 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008098 @NonNull
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008099 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008100 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02008101 final IAudioService service = getService();
8102 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07008103 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02008104 } catch (RemoteException e) {
8105 throw e.rethrowFromSystemServer();
8106 }
François Gaffieadcd00a2018-09-18 17:06:26 +02008107 }
8108
8109 /**
8110 * @hide
8111 * Callback registered by client to be notified upon volume group change.
8112 */
8113 @SystemApi
8114 public abstract static class VolumeGroupCallback {
8115 /**
8116 * Callback method called upon audio volume group change.
8117 * @param group the group for which the volume has changed
8118 */
8119 public void onAudioVolumeGroupChanged(int group, int flags) {}
8120 }
8121
8122 /**
8123 * @hide
8124 * Register an audio volume group change listener.
8125 * @param callback the {@link VolumeGroupCallback} to register
8126 */
8127 @SystemApi
8128 public void registerVolumeGroupCallback(
8129 @NonNull Executor executor,
8130 @NonNull VolumeGroupCallback callback) {
8131 Preconditions.checkNotNull(executor, "executor must not be null");
8132 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8133 sAudioAudioVolumeGroupChangedHandler.init();
8134 // TODO: make use of executor
8135 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
8136 }
8137
8138 /**
8139 * @hide
8140 * Unregister an audio volume group change listener.
8141 * @param callback the {@link VolumeGroupCallback} to unregister
8142 */
8143 @SystemApi
8144 public void unregisterVolumeGroupCallback(
8145 @NonNull VolumeGroupCallback callback) {
8146 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8147 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
8148 }
jiabin39940752018-04-02 18:18:45 -07008149
jiabinad225202019-03-20 15:22:50 -07008150 /**
8151 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07008152 *
8153 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07008154 * @param uri the {@link Uri} of the asset.
8155 * @return true if the assert contains haptic channels.
8156 * @hide
8157 */
jiabincfcf1032021-07-01 16:30:50 -07008158 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
8159 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07008160 try {
jiabincfcf1032021-07-01 16:30:50 -07008161 extractor.setDataSource(context, uri, null);
8162 for (int i = 0; i < extractor.getTrackCount(); i++) {
8163 MediaFormat format = extractor.getTrackFormat(i);
8164 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
8165 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
8166 return true;
8167 }
8168 }
8169 } catch (IOException e) {
8170 Log.e(TAG, "hasHapticChannels failure:" + e);
8171 }
8172 return false;
8173 }
8174
8175 /**
8176 * Return if an asset contains haptic channels or not.
8177 *
8178 * @param context the {@link Context} to resolve the uri.
8179 * @param uri the {@link Uri} of the asset.
8180 * @return true if the assert contains haptic channels.
8181 * @hide
8182 */
8183 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
8184 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07008185
jiabincfcf1032021-07-01 16:30:50 -07008186 if (context != null) {
8187 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07008188 }
8189
8190 Context cachedContext = sContext.get();
8191 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07008192 if (DEBUG) {
8193 Log.d(TAG, "Try to use static context to query if having haptic channels");
8194 }
jiabin0f3339c2021-07-09 11:50:07 -07008195 return hasHapticChannelsImpl(cachedContext, uri);
8196 }
8197
8198 // Try with audio service context, this may fail to get correct result.
8199 if (DEBUG) {
8200 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
8201 }
8202 try {
8203 return getService().hasHapticChannels(uri);
8204 } catch (RemoteException e) {
8205 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07008206 }
8207 }
8208
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07008209 /**
8210 * Set whether or not there is an active RTT call.
8211 * This method should be called by Telecom service.
8212 * @hide
8213 * TODO: make this a @SystemApi
8214 */
8215 public static void setRttEnabled(boolean rttEnabled) {
8216 try {
8217 getService().setRttEnabled(rttEnabled);
8218 } catch (RemoteException e) {
8219 throw e.rethrowFromSystemServer();
8220 }
8221 }
8222
Jin Seok Park16aeba382020-08-06 12:52:54 +09008223 /**
8224 * Adjusts the volume of the most relevant stream, or the given fallback
8225 * stream.
8226 * <p>
8227 * This method should only be used by applications that replace the
8228 * platform-wide management of audio settings or the main telephony
8229 * application.
8230 * <p>
8231 * This method has no effect if the device implements a fixed volume policy
8232 * as indicated by {@link #isVolumeFixed()}.
8233 * <p>This API checks if the caller has the necessary permissions based on the provided
8234 * component name, uid, and pid values.
8235 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
8236 *
8237 * @param suggestedStreamType The stream type that will be used if there
8238 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
8239 * valid here.
8240 * @param direction The direction to adjust the volume. One of
8241 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
8242 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
8243 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
8244 * @param flags One or more flags.
8245 * @param packageName the package name of client application
8246 * @param uid the uid of client application
8247 * @param pid the pid of client application
8248 * @param targetSdkVersion the target sdk version of client application
8249 * @see #adjustVolume(int, int)
8250 * @see #adjustStreamVolume(int, int, int)
8251 * @see #setStreamVolume(int, int, int)
8252 * @see #isVolumeFixed()
8253 *
8254 * @hide
8255 */
8256 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8257 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
8258 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8259 try {
8260 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
8261 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8262 } catch (RemoteException e) {
8263 throw e.rethrowFromSystemServer();
8264 }
8265 }
8266
8267 /**
8268 * Adjusts the volume of a particular stream by one step in a direction.
8269 * <p>
8270 * This method should only be used by applications that replace the platform-wide
8271 * management of audio settings or the main telephony application.
8272 * <p>This method has no effect if the device implements a fixed volume policy
8273 * as indicated by {@link #isVolumeFixed()}.
8274 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
8275 * unless the app has been granted Do Not Disturb Access.
8276 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8277 * <p>This API checks if the caller has the necessary permissions based on the provided
8278 * component name, uid, and pid values.
8279 * See {@link #adjustStreamVolume(int, int, int)}.
8280 *
8281 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
8282 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
8283 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
8284 * @param direction The direction to adjust the volume. One of
8285 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
8286 * {@link #ADJUST_SAME}.
8287 * @param flags One or more flags.
8288 * @param packageName the package name of client application
8289 * @param uid the uid of client application
8290 * @param pid the pid of client application
8291 * @param targetSdkVersion the target sdk version of client application
8292 * @see #adjustVolume(int, int)
8293 * @see #setStreamVolume(int, int, int)
8294 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
8295 * and the caller is not granted notification policy access.
8296 *
8297 * @hide
8298 */
8299 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8300 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
8301 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8302 try {
8303 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
8304 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8305 } catch (RemoteException e) {
8306 throw e.rethrowFromSystemServer();
8307 }
8308 }
8309
8310 /**
8311 * Sets the volume index for a particular stream.
8312 * <p>This method has no effect if the device implements a fixed volume policy
8313 * as indicated by {@link #isVolumeFixed()}.
8314 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
8315 * the app has been granted Do Not Disturb Access.
8316 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8317 * <p>This API checks if the caller has the necessary permissions based on the provided
8318 * component name, uid, and pid values.
8319 * See {@link #setStreamVolume(int, int, int)}.
8320 *
8321 * @param streamType The stream whose volume index should be set.
8322 * @param index The volume index to set. See
8323 * {@link #getStreamMaxVolume(int)} for the largest valid value.
8324 * @param flags One or more flags.
8325 * @param packageName the package name of client application
8326 * @param uid the uid of client application
8327 * @param pid the pid of client application
8328 * @param targetSdkVersion the target sdk version of client application
8329 * @see #getStreamMaxVolume(int)
8330 * @see #getStreamVolume(int)
8331 * @see #isVolumeFixed()
8332 * @throws SecurityException if the volume change triggers a Do Not Disturb change
8333 * and the caller is not granted notification policy access.
8334 *
8335 * @hide
8336 */
8337 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8338 public void setStreamVolumeForUid(int streamType, int index, int flags,
8339 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8340 try {
8341 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
8342 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8343 } catch (RemoteException e) {
8344 throw e.rethrowFromSystemServer();
8345 }
8346 }
8347
8348
hjin81.lee4e984e52019-12-05 14:34:52 +09008349 /** @hide
8350 * TODO: make this a @SystemApi */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008351 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
hjin81.lee4e984e52019-12-05 14:34:52 +09008352 public void setMultiAudioFocusEnabled(boolean enabled) {
8353 try {
8354 getService().setMultiAudioFocusEnabled(enabled);
8355 } catch (RemoteException e) {
8356 throw e.rethrowFromSystemServer();
8357 }
8358 }
8359
Eric Laurent43a78de2020-07-24 17:11:15 -07008360
8361 /**
8362 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
8363 * For more details on Hardware A/V synchronization please refer to
8364 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
8365 * media tunneling documentation</a>.
8366 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
8367 * @return the HW A/V sync ID for this audio session (an integer different from 0).
8368 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
8369 */
8370 public int getAudioHwSyncForSession(int sessionId) {
8371 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
8372 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
8373 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
8374 }
8375 return hwSyncId;
8376 }
8377
Eric Laurentb36d4a12020-10-09 09:52:49 -07008378 /**
8379 * Selects the audio device that should be used for communication use cases, for instance voice
8380 * or video calls. This method can be used by voice or video chat applications to select a
8381 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01008382 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
Eric Laurent6aa23612022-11-18 16:08:20 +01008383 * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role
8384 * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching
8385 * source device is selected automatically by the platform.
8386 * <p>The selection is active as long as the requesting application process lives, until
Eric Laurent7412f572021-02-11 15:10:31 +01008387 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008388 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01008389 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008390 * <p>In case of simultaneous requests by multiple applications the priority is given to the
8391 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
8392 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
8393 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
8394 * telephony application with permission
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008395 * {@link Manifest.permission#MODIFY_PHONE_STATE}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008396 * <p> If the requested devices is not currently available, the request will be rejected and
8397 * the method will return false.
8398 * <p>This API replaces the following deprecated APIs:
8399 * <ul>
8400 * <li> {@link #startBluetoothSco()}
8401 * <li> {@link #stopBluetoothSco()}
8402 * <li> {@link #setSpeakerphoneOn(boolean)}
8403 * </ul>
8404 * <h4>Example</h4>
8405 * <p>The example below shows how to enable and disable speakerphone mode.
8406 * <pre class="prettyprint">
8407 * // Get an AudioManager instance
8408 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01008409 * AudioDeviceInfo speakerDevice = null;
8410 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
8411 * for (AudioDeviceInfo device : devices) {
8412 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
8413 * speakerDevice = device;
8414 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008415 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008416 * }
8417 * if (speakerDevice != null) {
8418 * // Turn speakerphone ON.
8419 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
8420 * if (!result) {
8421 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008422 * }
Eric Laurent9a404482021-03-09 19:58:39 +01008423 * // Turn speakerphone OFF.
8424 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008425 * }
8426 * </pre>
8427 * @param device the requested audio device.
8428 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
8429 * @throws IllegalArgumentException If an invalid device is specified.
8430 */
Eric Laurent7412f572021-02-11 15:10:31 +01008431 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008432 Objects.requireNonNull(device);
8433 try {
8434 if (device.getId() == 0) {
Eric Laurentc18e5a12023-01-20 19:30:09 +01008435 Log.w(TAG, "setCommunicationDevice: device not found: " + device);
8436 return false;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008437 }
Eric Laurent7412f572021-02-11 15:10:31 +01008438 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008439 } catch (RemoteException e) {
8440 throw e.rethrowFromSystemServer();
8441 }
8442 }
8443
8444 /**
8445 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01008446 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008447 */
Eric Laurent7412f572021-02-11 15:10:31 +01008448 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008449 try {
Eric Laurent7412f572021-02-11 15:10:31 +01008450 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07008451 } catch (RemoteException e) {
8452 throw e.rethrowFromSystemServer();
8453 }
8454 }
8455
8456 /**
8457 * Returns currently selected audio device for communication.
8458 * <p>This API replaces the following deprecated APIs:
8459 * <ul>
8460 * <li> {@link #isBluetoothScoOn()}
8461 * <li> {@link #isSpeakerphoneOn()}
8462 * </ul>
8463 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01008464 * currently selected for communication use cases. Can be null on platforms
8465 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008466 * is used.
8467 */
8468 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01008469 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008470 try {
8471 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01008472 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
8473 } catch (RemoteException e) {
8474 throw e.rethrowFromSystemServer();
8475 }
8476 }
8477
8478 /**
8479 * Returns a list of audio devices that can be selected for communication use cases via
8480 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
8481 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
8482 */
8483 @NonNull
8484 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
8485 try {
8486 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
8487 int[] portIds = getService().getAvailableCommunicationDeviceIds();
8488 for (int portId : portIds) {
8489 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
8490 if (device == null) {
8491 continue;
8492 }
8493 devices.add(device);
8494 }
8495 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008496 } catch (RemoteException e) {
8497 throw e.rethrowFromSystemServer();
8498 }
8499 }
8500
8501 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01008502 * Returns a list of direct {@link AudioProfile} that are supported for the specified
8503 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
8504 * is possible.
8505 *
8506 * <p>Direct playback means that the audio stream is not resampled or downmixed
8507 * by the framework. Checking for direct support can help the app select the representation
8508 * of audio content that most closely matches the capabilities of the device and peripherals
8509 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
8510 * or mixed with other streams, if needed.
8511 * <p>When using this information to inform your application which audio format to play,
8512 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
8513 * @param attributes a non-null {@link AudioAttributes} instance.
8514 * @return a list of {@link AudioProfile}
8515 */
8516 @NonNull
8517 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
8518 Objects.requireNonNull(attributes);
8519 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
8520 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
8521 if (status != SUCCESS) {
8522 Log.w(TAG, "getDirectProfilesForAttributes failed.");
8523 return new ArrayList<>();
8524 }
8525 return audioProfilesList;
8526 }
8527
8528 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008529 * @hide
8530 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
8531 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
8532 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
8533 * The method will return null if no device of the provided type is connected.
8534 * If more than one device of the provided type is connected, an object corresponding to the
8535 * first device encountered in the enumeration list will be returned.
8536 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01008537 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008538 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
8539 * @throws IllegalArgumentException If an invalid device type is specified.
8540 */
8541 @TestApi
8542 @Nullable
8543 public static AudioDeviceInfo getDeviceInfoFromType(
8544 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01008545 return getDeviceInfoFromTypeAndAddress(deviceType, null);
8546 }
8547
Eric Laurent78eef3a2021-11-09 16:10:42 +01008548 /**
Eric Laurent7412f572021-02-11 15:10:31 +01008549 * @hide
8550 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
8551 * address provided.
8552 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
8553 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
8554 * If a null address is provided, the matching will happen on the type only.
8555 * The method will return null if no device of the provided type and address is connected.
8556 * If more than one device of the provided type is connected, an object corresponding to the
8557 * first device encountered in the enumeration list will be returned.
8558 * @param type The device device for which an <code>AudioDeviceInfo</code>
8559 * object is queried.
8560 * @param address The device address for which an <code>AudioDeviceInfo</code>
8561 * object is queried or null if requesting match on type only.
8562 * @return An AudioDeviceInfo object or null if no matching device is connected.
8563 * @throws IllegalArgumentException If an invalid device type is specified.
8564 */
8565 @Nullable
8566 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
8567 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008568 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01008569 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008570 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01008571 if (device.getType() == type) {
8572 deviceForType = device;
8573 if (address == null || address.equals(device.getAddress())) {
8574 return device;
8575 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008576 }
8577 }
Eric Laurent7412f572021-02-11 15:10:31 +01008578 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07008579 }
8580
8581 /**
8582 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01008583 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008584 */
8585 public interface OnCommunicationDeviceChangedListener {
8586 /**
8587 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01008588 * @param device the audio device requested for communication use cases.
8589 * Can be null on platforms not supporting
8590 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008591 */
8592 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
8593 }
8594
8595 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008596 * manages the OnCommunicationDeviceChangedListener listeners and the
8597 * CommunicationDeviceDispatcherStub
8598 */
8599 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
8600 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
8601 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07008602 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01008603 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008604 * @param executor
8605 * @param listener
8606 */
8607 public void addOnCommunicationDeviceChangedListener(
8608 @NonNull @CallbackExecutor Executor executor,
8609 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008610 mCommDeviceChangedListenerMgr.addListener(
8611 executor, listener, "addOnCommunicationDeviceChangedListener",
8612 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07008613 }
8614
8615 /**
8616 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01008617 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07008618 * @param listener
8619 */
8620 public void removeOnCommunicationDeviceChangedListener(
8621 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008622 mCommDeviceChangedListenerMgr.removeListener(listener,
8623 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07008624 }
8625
Eric Laurentb36d4a12020-10-09 09:52:49 -07008626 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008627 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008628
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008629 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008630 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07008631 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008632 if (register) {
8633 getService().registerCommunicationDeviceDispatcher(this);
8634 } else {
8635 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07008636 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008637 } catch (RemoteException e) {
8638 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07008639 }
8640 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008641
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008642 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008643 public void dispatchCommunicationDeviceChanged(int portId) {
8644 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08008645 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008646 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07008647 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07008648 }
8649
Eric Laurent78eef3a2021-11-09 16:10:42 +01008650
8651 /**
8652 * @hide
8653 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
8654 * PSTN call.
8655 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
8656 * an AudioTrack for call uplink audio injection and
8657 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
8658 * an AudioRecord for call downlink audio extraction.
8659 * @return true if PSTN call audio is accessible, false otherwise.
8660 */
8661 @TestApi
8662 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008663 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01008664 public boolean isPstnCallAudioInterceptable() {
8665 final IAudioService service = getService();
8666 try {
8667 return service.isPstnCallAudioInterceptable();
8668 } catch (RemoteException e) {
8669 throw e.rethrowFromSystemServer();
8670 }
8671 }
8672
8673 /** @hide */
8674 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
8675 CALL_REDIRECT_NONE,
8676 CALL_REDIRECT_PSTN,
8677 CALL_REDIRECT_VOIP }
8678 )
8679 @Retention(RetentionPolicy.SOURCE)
8680 public @interface CallRedirectionMode {}
8681
8682 /**
8683 * Not used for call redirection
8684 * @hide
8685 */
8686 public static final int CALL_REDIRECT_NONE = 0;
8687 /**
8688 * Used to redirect PSTN call
8689 * @hide
8690 */
8691 public static final int CALL_REDIRECT_PSTN = 1;
8692 /**
8693 * Used to redirect VoIP call
8694 * @hide
8695 */
8696 public static final int CALL_REDIRECT_VOIP = 2;
8697
8698
8699 private @CallRedirectionMode int getCallRedirectMode() {
8700 int mode = getMode();
8701 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
8702 || mode == MODE_CALL_REDIRECT) {
8703 return CALL_REDIRECT_PSTN;
8704 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
8705 return CALL_REDIRECT_VOIP;
8706 }
8707 return CALL_REDIRECT_NONE;
8708 }
8709
8710 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
8711 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
8712 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
8713 throw new UnsupportedOperationException(" Unsupported encoding ");
8714 }
8715 if (format.getSampleRate() < 8000
8716 || format.getSampleRate() > 48000) {
8717 throw new UnsupportedOperationException(" Unsupported sample rate ");
8718 }
8719 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
8720 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
8721 throw new UnsupportedOperationException(" Unsupported output channel mask ");
8722 }
8723 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
8724 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
8725 throw new UnsupportedOperationException(" Unsupported input channel mask ");
8726 }
8727 }
8728
8729 class CallIRedirectionClientInfo {
8730 public WeakReference trackOrRecord;
8731 public int redirectMode;
8732 }
8733
8734 private Object mCallRedirectionLock = new Object();
8735 @GuardedBy("mCallRedirectionLock")
8736 private CallInjectionModeChangedListener mCallRedirectionModeListener;
8737 @GuardedBy("mCallRedirectionLock")
8738 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
8739
8740 /**
8741 * @hide
8742 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
8743 * This can be used for functions like call screening or call audio redirection and is reserved
8744 * to system apps with privileged permission.
8745 * @param format the desired audio format for audio playback.
8746 * p>Formats accepted are:
8747 * <ul>
8748 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8749 * <li><em>Channel mask</em> - Mono or Stereo </li>
8750 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8751 * </ul>
8752 *
8753 * @return The AudioTrack used for audio injection
8754 * @throws NullPointerException if AudioFormat argument is null.
8755 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8756 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8757 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8758 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8759 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8760 * or MODE_COMMUNICATION_REDIRECT.
8761 */
8762 @TestApi
8763 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008764 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01008765 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
8766 Objects.requireNonNull(format);
8767 checkCallRedirectionFormat(format, true /* isOutput */);
8768
8769 AudioTrack track = null;
8770 int redirectMode = getCallRedirectMode();
8771 if (redirectMode == CALL_REDIRECT_NONE) {
8772 throw new IllegalStateException(
8773 " not available in mode " + AudioSystem.modeToString(getMode()));
8774 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8775 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8776 }
8777
8778 track = new AudioTrack.Builder()
8779 .setAudioAttributes(new AudioAttributes.Builder()
8780 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
8781 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
8782 .build())
8783 .setAudioFormat(format)
8784 .setCallRedirectionMode(redirectMode)
8785 .build();
8786
8787 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
8788 synchronized (mCallRedirectionLock) {
8789 if (mCallRedirectionModeListener == null) {
8790 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8791 try {
8792 addOnModeChangedListener(
8793 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8794 } catch (Exception e) {
8795 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8796 mCallRedirectionModeListener = null;
8797 throw new UnsupportedOperationException(" Cannot register mode listener ");
8798 }
8799 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8800 }
8801 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8802 info.redirectMode = redirectMode;
8803 info.trackOrRecord = new WeakReference<AudioTrack>(track);
8804 mCallIRedirectionClients.add(info);
8805 }
8806 } else {
8807 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
8808 }
8809 return track;
8810 }
8811
8812 /**
8813 * @hide
8814 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
8815 * This can be used for functions like call screening or call audio redirection and is reserved
8816 * to system apps with privileged permission.
8817 * @param format the desired audio format for audio capture.
8818 *<p>Formats accepted are:
8819 * <ul>
8820 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8821 * <li><em>Channel mask</em> - Mono or Stereo </li>
8822 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8823 * </ul>
8824 *
8825 * @return The AudioRecord used for audio extraction
8826 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8827 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8828 * @throws NullPointerException if AudioFormat argument is null.
8829 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8830 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8831 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8832 * or MODE_COMMUNICATION_REDIRECT.
8833 */
8834 @TestApi
8835 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008836 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
Eric Laurent78eef3a2021-11-09 16:10:42 +01008837 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
8838 Objects.requireNonNull(format);
8839 checkCallRedirectionFormat(format, false /* isOutput */);
8840
8841 AudioRecord record = null;
8842 int redirectMode = getCallRedirectMode();
8843 if (redirectMode == CALL_REDIRECT_NONE) {
8844 throw new IllegalStateException(
8845 " not available in mode " + AudioSystem.modeToString(getMode()));
8846 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8847 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8848 }
8849
8850 record = new AudioRecord.Builder()
8851 .setAudioAttributes(new AudioAttributes.Builder()
8852 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
8853 .build())
8854 .setAudioFormat(format)
8855 .setCallRedirectionMode(redirectMode)
8856 .build();
8857
8858 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
8859 synchronized (mCallRedirectionLock) {
8860 if (mCallRedirectionModeListener == null) {
8861 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8862 try {
8863 addOnModeChangedListener(
8864 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8865 } catch (Exception e) {
8866 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8867 mCallRedirectionModeListener = null;
8868 throw new UnsupportedOperationException(" Cannot register mode listener ");
8869 }
8870 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8871 }
8872 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8873 info.redirectMode = redirectMode;
8874 info.trackOrRecord = new WeakReference<AudioRecord>(record);
8875 mCallIRedirectionClients.add(info);
8876 }
8877 } else {
8878 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
8879 }
8880 return record;
8881 }
8882
8883 class CallInjectionModeChangedListener implements OnModeChangedListener {
8884 @Override
8885 public void onModeChanged(@AudioMode int mode) {
8886 synchronized (mCallRedirectionLock) {
8887 final ArrayList<CallIRedirectionClientInfo> clientInfos =
8888 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
8889 for (CallIRedirectionClientInfo info : clientInfos) {
8890 Object trackOrRecord = info.trackOrRecord.get();
8891 if (trackOrRecord != null) {
8892 if ((info.redirectMode == CALL_REDIRECT_PSTN
8893 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
8894 && mode != MODE_CALL_REDIRECT)
8895 || (info.redirectMode == CALL_REDIRECT_VOIP
8896 && mode != MODE_IN_COMMUNICATION
8897 && mode != MODE_COMMUNICATION_REDIRECT)) {
8898 if (trackOrRecord instanceof AudioTrack) {
8899 AudioTrack track = (AudioTrack) trackOrRecord;
8900 track.release();
8901 } else {
8902 AudioRecord record = (AudioRecord) trackOrRecord;
8903 record.release();
8904 }
8905 mCallIRedirectionClients.remove(info);
8906 }
8907 }
8908 }
8909 if (mCallIRedirectionClients.isEmpty()) {
8910 try {
8911 if (mCallRedirectionModeListener != null) {
8912 removeOnModeChangedListener(mCallRedirectionModeListener);
8913 }
8914 } catch (Exception e) {
8915 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
8916 } finally {
8917 mCallRedirectionModeListener = null;
8918 mCallIRedirectionClients = null;
8919 }
8920 }
8921 }
8922 }
8923 }
8924
Paul McLeane3383cc2015-05-08 11:41:20 -07008925 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008926 // audio device connection-dependent muting
8927 /**
8928 * @hide
8929 * Mute a set of playback use cases until a given audio device is connected.
8930 * Automatically unmute upon connection of the device, or after the given timeout, whichever
8931 * happens first.
8932 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
8933 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
8934 * device connects
8935 * @param device the audio device expected to connect within the timeout duration
8936 * @param timeout the maximum amount of time to wait for the device connection
8937 * @param timeUnit the unit for the timeout
8938 * @throws IllegalStateException when trying to issue the command while another is already in
8939 * progress and hasn't been cancelled by
8940 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8941 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8942 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8943 */
8944 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008945 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008946 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8947 @NonNull AudioDeviceAttributes device,
8948 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8949 if (timeout <= 0) {
8950 throw new IllegalArgumentException("Timeout must be greater than 0");
8951 }
8952 Objects.requireNonNull(usagesToMute);
8953 if (usagesToMute.length == 0) {
8954 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8955 }
8956 Objects.requireNonNull(device);
8957 Objects.requireNonNull(timeUnit);
8958 try {
8959 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8960 } catch (RemoteException e) {
8961 throw e.rethrowFromSystemServer();
8962 }
8963 }
8964
8965 /**
8966 * @hide
8967 * Query which audio device, if any, is causing some playback use cases to be muted until it
8968 * connects.
8969 * @return the audio device used in
8970 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8971 * if there is no active muting command (either because the muting command was not issued
8972 * or because it timed out)
8973 */
8974 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008975 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008976 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8977 try {
8978 return getService().getMutingExpectedDevice();
8979 } catch (RemoteException e) {
8980 throw e.rethrowFromSystemServer();
8981 }
8982 }
8983
8984 /**
8985 * @hide
8986 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8987 * command.
8988 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8989 * command was issued.
8990 * @throws IllegalStateException when trying to issue the command for a device whose connection
8991 * is not anticipated by a previous call to
8992 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8993 */
8994 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00008995 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008996 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8997 throws IllegalStateException {
8998 Objects.requireNonNull(device);
8999 try {
9000 getService().cancelMuteAwaitConnection(device);
9001 } catch (RemoteException e) {
9002 throw e.rethrowFromSystemServer();
9003 }
9004 }
9005
9006 /**
9007 * @hide
9008 * A callback class to receive events about the muting and unmuting of playback use cases
9009 * conditional on the upcoming connection of an audio device.
9010 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
9011 */
9012 @SystemApi
9013 public abstract static class MuteAwaitConnectionCallback {
9014
9015 /**
9016 * An event where the expected audio device connected
9017 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9018 */
9019 public static final int EVENT_CONNECTION = 1;
9020 /**
9021 * An event where the expected audio device failed connect before the timeout happened
9022 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9023 */
9024 public static final int EVENT_TIMEOUT = 2;
9025 /**
9026 * An event where the {@code muteAwaitConnection()} command
9027 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
9028 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9029 */
9030 public static final int EVENT_CANCEL = 3;
9031
9032 /** @hide */
9033 @IntDef(flag = false, prefix = "EVENT_", value = {
9034 EVENT_CONNECTION,
9035 EVENT_TIMEOUT,
9036 EVENT_CANCEL }
9037 )
9038 @Retention(RetentionPolicy.SOURCE)
9039 public @interface UnmuteEvent {}
9040
9041 /**
9042 * Called when a number of playback use cases are muted in response to a call to
9043 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
9044 * @param device the audio device whose connection is expected. Playback use cases are
9045 * unmuted when that device connects
9046 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
9047 * playback use cases.
9048 */
9049 public void onMutedUntilConnection(
9050 @NonNull AudioDeviceAttributes device,
9051 @NonNull int[] mutedUsages) {}
9052
9053 /**
9054 * Called when an event occurred that caused playback uses cases to be unmuted
9055 * @param unmuteEvent the nature of the event
9056 * @param device the device that was expected to connect
9057 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
9058 * the event occurred
9059 */
9060 public void onUnmutedEvent(
9061 @UnmuteEvent int unmuteEvent,
9062 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
9063 }
9064
9065
9066 /**
9067 * @hide
9068 * Register a callback to receive updates on the playback muting conditional on a specific
9069 * audio device connection.
9070 * @param executor the {@link Executor} handling the callback
9071 * @param callback the callback to register
9072 */
9073 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009074 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009075 public void registerMuteAwaitConnectionCallback(
9076 @NonNull @CallbackExecutor Executor executor,
9077 @NonNull MuteAwaitConnectionCallback callback) {
9078 synchronized (mMuteAwaitConnectionListenerLock) {
9079 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9080 MuteAwaitConnectionDispatcherStub> res =
9081 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
9082 executor, callback, mMuteAwaitConnectionListeners,
9083 mMuteAwaitConnDispatcherStub,
9084 () -> new MuteAwaitConnectionDispatcherStub(),
9085 stub -> stub.register(true));
9086 mMuteAwaitConnectionListeners = res.first;
9087 mMuteAwaitConnDispatcherStub = res.second;
9088 }
9089 }
9090
9091 /**
9092 * @hide
9093 * Unregister a previously registered callback for playback muting conditional on device
9094 * connection.
9095 * @param callback the callback to unregister
9096 */
9097 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009098 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009099 public void unregisterMuteAwaitConnectionCallback(
9100 @NonNull MuteAwaitConnectionCallback callback) {
9101 synchronized (mMuteAwaitConnectionListenerLock) {
9102 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9103 MuteAwaitConnectionDispatcherStub> res =
9104 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
9105 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
9106 stub -> stub.register(false));
9107 mMuteAwaitConnectionListeners = res.first;
9108 mMuteAwaitConnDispatcherStub = res.second;
9109 }
9110 }
9111
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009112 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009113 * Add UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009114 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009115 * @param assistantUids UIDs of the services that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009116 *
9117 * @hide
9118 */
9119 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009120 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009121 public void addAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009122 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009123 getService().addAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009124 } catch (RemoteException e) {
9125 throw e.rethrowFromSystemServer();
9126 }
9127 }
9128
9129 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009130 * Remove UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009131 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009132 * @param assistantUids UIDs of the services that should be remove.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009133 *
9134 * @hide
9135 */
9136 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009137 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009138 public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009139 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009140 getService().removeAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009141 } catch (RemoteException e) {
9142 throw e.rethrowFromSystemServer();
9143 }
9144 }
9145
9146 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009147 * Get the assistants UIDs that been added with the
9148 * {@link #addAssistantServicesUids(int[])} and not yet removed with
9149 * {@link #removeAssistantServicesUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009150 *
Oscar Azucena3ae33762022-03-04 04:44:59 +00009151 * <p> Note that during native audioserver crash and after boot up the list of assistant
9152 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
9153 * Just after user switch, the list of assistant will also reset to empty.
9154 * In both cases,The component's UID of the assistiant role or assistant setting will be
9155 * automitically added to the list by the audio service.
9156 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009157 * @return array of assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009158 *
9159 * @hide
9160 */
9161 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009162 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009163 public @NonNull int[] getAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009164 try {
9165 int[] uids = getService().getAssistantServicesUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00009166 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009167 } catch (RemoteException e) {
9168 throw e.rethrowFromSystemServer();
9169 }
9170 }
9171
9172 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009173 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
9174 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
9175 * In this manner calling the API with an empty array will remove all UIDs previously set.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009176 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009177 * @param assistantUids UIDs of the services that can be considered active assistant. Can be
9178 * an empty array, for this no UID will be considered active.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009179 *
9180 * <p> Note that during audio service crash reset and after boot up the list of active assistant
Oscar Azucena88467fe2022-02-15 21:55:11 +00009181 * 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 -08009182 * Just after user switch the list of active assistant will also reset to empty.
9183 *
9184 * @hide
9185 */
9186 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009187 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009188 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009189 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00009190 getService().setActiveAssistantServiceUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009191 } catch (RemoteException e) {
9192 throw e.rethrowFromSystemServer();
9193 }
9194 }
9195
9196 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00009197 * Get active assistant UIDs last set with the
9198 * {@link #setActiveAssistantServiceUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009199 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00009200 * @return array of active assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009201 *
9202 * @hide
9203 */
9204 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009205 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00009206 public @NonNull int[] getActiveAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009207 try {
9208 int[] uids = getService().getActiveAssistantServiceUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00009209 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08009210 } catch (RemoteException e) {
9211 throw e.rethrowFromSystemServer();
9212 }
9213 }
9214
jiabinfe6b7f12022-02-04 18:45:44 +00009215 /**
Shunkai Yao601b6132022-11-22 01:47:48 +00009216 * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio
9217 * HAL found, null will be returned.
jiabinfe6b7f12022-02-04 18:45:44 +00009218 *
Shunkai Yao601b6132022-11-22 01:47:48 +00009219 * @return @see @link #AudioHalVersionInfo The version of Audio HAL.
jiabinfe6b7f12022-02-04 18:45:44 +00009220 * @hide
9221 */
9222 @TestApi
Shunkai Yao601b6132022-11-22 01:47:48 +00009223 public static @Nullable AudioHalVersionInfo getHalVersion() {
jiabinfe6b7f12022-02-04 18:45:44 +00009224 try {
9225 return getService().getHalVersion();
9226 } catch (RemoteException e) {
9227 Log.e(TAG, "Error querying getHalVersion", e);
9228 throw e.rethrowFromSystemServer();
9229 }
9230 }
9231
jiabin89f87ed2022-12-01 22:55:05 +00009232 //====================================================================
9233 // Preferred mixer attributes
9234
9235 /**
Jiabin Huang11285ff2023-02-03 01:04:58 +00009236 * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixer
jiabin89f87ed2022-12-01 22:55:05 +00009237 * attributes via {@link #setPreferredMixerAttributes(
9238 * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}.
Jiabin Huang11285ff2023-02-03 01:04:58 +00009239 * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes. An
9240 * empty list may be returned for all other types of devices as they may not allow dynamic
9241 * configuration.
jiabin89f87ed2022-12-01 22:55:05 +00009242 *
9243 * @param device the device to query
9244 * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes
9245 * for the given device.
9246 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9247 */
9248 @NonNull
9249 public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) {
9250 Objects.requireNonNull(device);
9251 List<AudioMixerAttributes> mixerAttrs = new ArrayList<>();
9252 return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs)
9253 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>();
9254 }
9255
9256 /**
9257 * Configures the mixer attributes for a particular {@link AudioAttributes} over a given
9258 * {@link AudioDeviceInfo}.
Jiabin Huang11285ff2023-02-03 01:04:58 +00009259 * <p>Call {@link #getSupportedMixerAttributes(AudioDeviceInfo)} to determine which mixer
9260 * attributes can be used with the given device.
jiabin89f87ed2022-12-01 22:55:05 +00009261 * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the
9262 * same uid is routed to the given audio device when calling this API, the output mixer/stream
9263 * will be configured with the values previously set via this API.
9264 * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)}
9265 * to cancel setting mixer attributes for this {@link AudioAttributes}.
9266 *
9267 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9268 * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When
9269 * playing audio targeted at the given device, use the same attributes for
9270 * playback.
9271 * @param device the device to be routed. Currently, only USB device will be allowed.
9272 * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the
9273 * given device, use the same {@link AudioFormat} for both playback
9274 * and the mixer attributes.
9275 * @return true only if the preferred mixer attributes are set successfully.
9276 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9277 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9278 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009279 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
jiabin89f87ed2022-12-01 22:55:05 +00009280 public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
9281 @NonNull AudioDeviceInfo device,
9282 @NonNull AudioMixerAttributes mixerAttributes) {
9283 Objects.requireNonNull(attributes);
9284 Objects.requireNonNull(device);
9285 Objects.requireNonNull(mixerAttributes);
9286 try {
9287 final int status = getService().setPreferredMixerAttributes(
9288 attributes, device.getId(), mixerAttributes);
9289 return status == AudioSystem.SUCCESS;
9290 } catch (RemoteException e) {
9291 throw e.rethrowFromSystemServer();
9292 }
9293 }
9294
9295 /**
9296 * Returns current preferred mixer attributes that is set via
9297 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9298 *
9299 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9300 * @param device the expected routing device
9301 * @return the preferred mixer attributes, which will be null when no preferred mixer attributes
9302 * have been set, or when they have been cleared.
9303 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9304 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9305 */
9306 @Nullable
9307 public AudioMixerAttributes getPreferredMixerAttributes(
9308 @NonNull AudioAttributes attributes,
9309 @NonNull AudioDeviceInfo device) {
9310 Objects.requireNonNull(attributes);
9311 Objects.requireNonNull(device);
9312 List<AudioMixerAttributes> mixerAttrList = new ArrayList<>();
9313 int ret = AudioSystem.getPreferredMixerAttributes(
9314 attributes, device.getId(), mixerAttrList);
9315 if (ret == AudioSystem.SUCCESS) {
9316 return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0);
9317 } else {
9318 Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret);
9319 return null;
9320 }
9321 }
9322
9323 /**
9324 * Clears the current preferred mixer attributes that were previously set via
9325 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9326 *
9327 * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared.
9328 * @param device the expected routing device
9329 * @return true only if the preferred mixer attributes are removed successfully.
9330 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9331 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9332 */
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009333 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
jiabin89f87ed2022-12-01 22:55:05 +00009334 public boolean clearPreferredMixerAttributes(
9335 @NonNull AudioAttributes attributes,
9336 @NonNull AudioDeviceInfo device) {
9337 Objects.requireNonNull(attributes);
9338 Objects.requireNonNull(device);
9339 try {
9340 final int status = getService().clearPreferredMixerAttributes(
9341 attributes, device.getId());
9342 return status == AudioSystem.SUCCESS;
9343 } catch (RemoteException e) {
9344 throw e.rethrowFromSystemServer();
9345 }
9346 }
9347
9348 /**
9349 * Interface to be notified of changes in the preferred mixer attributes.
9350 * <p>Note that this listener will only be invoked whenever
9351 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9352 * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device
9353 * disconnection causes a change in preferred mixer attributes.
9354 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9355 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9356 */
9357 public interface OnPreferredMixerAttributesChangedListener {
9358 /**
9359 * Called on the listener to indicate that the preferred mixer attributes for the audio
9360 * attributes over the given device has changed.
9361 *
9362 * @param attributes the audio attributes for playback
9363 * @param device the targeted device
9364 * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for
9365 * preferred mixer attributes or null if preferred mixer attributes
9366 * is cleared
9367 */
9368 void onPreferredMixerAttributesChanged(
9369 @NonNull AudioAttributes attributes,
9370 @NonNull AudioDeviceInfo device,
9371 @Nullable AudioMixerAttributes mixerAttributes);
9372 }
9373
9374 /**
9375 * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the
9376 * {@link PreferredMixerAttributesDispatcherStub}.
9377 */
9378 private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener>
9379 mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager();
9380
9381 /**
9382 * Adds a listener for being notified of changes to the preferred mixer attributes.
9383 * @param executor the executor to execute the callback
9384 * @param listener the listener to be notified of changes in the preferred mixer attributes.
9385 */
9386 public void addOnPreferredMixerAttributesChangedListener(
9387 @NonNull @CallbackExecutor Executor executor,
9388 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9389 Objects.requireNonNull(executor);
9390 Objects.requireNonNull(listener);
9391 mPrefMixerAttributesListenerMgr.addListener(executor, listener,
9392 "addOnPreferredMixerAttributesChangedListener",
9393 () -> new PreferredMixerAttributesDispatcherStub());
9394 }
9395
9396 /**
9397 * Removes a previously added listener of changes to the preferred mixer attributes.
9398 * @param listener the listener to be notified of changes in the preferred mixer attributes,
9399 * which were added via {@link #addOnPreferredMixerAttributesChangedListener(
9400 * Executor, OnPreferredMixerAttributesChangedListener)}.
9401 */
9402 public void removeOnPreferredMixerAttributesChangedListener(
9403 @NonNull OnPreferredMixerAttributesChangedListener listener) {
9404 Objects.requireNonNull(listener);
9405 mPrefMixerAttributesListenerMgr.removeListener(listener,
9406 "removeOnPreferredMixerAttributesChangedListener");
9407 }
9408
9409 private final class PreferredMixerAttributesDispatcherStub
9410 extends IPreferredMixerAttributesDispatcher.Stub
9411 implements CallbackUtil.DispatcherStub {
9412
9413 @Override
9414 public void register(boolean register) {
9415 try {
9416 if (register) {
9417 getService().registerPreferredMixerAttributesDispatcher(this);
9418 } else {
9419 getService().unregisterPreferredMixerAttributesDispatcher(this);
9420 }
9421 } catch (RemoteException e) {
9422 e.rethrowFromSystemServer();
9423 }
9424 }
9425
9426 @Override
9427 public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr,
9428 int deviceId,
9429 @Nullable AudioMixerAttributes mixerAttr) {
9430 // TODO: If the device is disconnected, we may not be able to find the device with
9431 // given device id. We need a better to carry the device information via binder.
9432 AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS);
9433 if (device == null) {
9434 Log.d(TAG, "Drop preferred mixer attributes changed as the device("
9435 + deviceId + ") is disconnected");
9436 return;
9437 }
9438 mPrefMixerAttributesListenerMgr.callListeners(
9439 (listener) -> listener.onPreferredMixerAttributesChanged(
9440 attr, device, mixerAttr));
9441 }
9442 }
9443
Eric Laurent3c474bc2022-12-16 17:24:32 +01009444 /**
9445 * Requests if the implementation supports controlling the latency modes
9446 * over the Bluetooth A2DP or LE Audio links.
9447 *
9448 * @return true if supported, false otherwise
9449 *
9450 * @hide
9451 */
9452 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009453 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +01009454 public boolean supportsBluetoothVariableLatency() {
9455 try {
9456 return getService().supportsBluetoothVariableLatency();
9457 } catch (RemoteException e) {
9458 throw e.rethrowFromSystemServer();
9459 }
9460 }
9461
9462 /**
9463 * Enables or disables the variable Bluetooth latency control mechanism in the
9464 * audio framework and the audio HAL. This does not apply to the latency mode control
9465 * on the spatializer output as this is a built-in feature.
9466 *
9467 * @hide
9468 */
9469 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009470 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +01009471 public void setBluetoothVariableLatencyEnabled(boolean enabled) {
9472 try {
9473 getService().setBluetoothVariableLatencyEnabled(enabled);
9474 } catch (RemoteException e) {
9475 throw e.rethrowFromSystemServer();
9476 }
9477 }
9478
9479 /**
9480 * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
9481 * @hide
9482 */
9483 @SystemApi
Jean-Michel Trivic4557822023-01-23 18:19:52 +00009484 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
Eric Laurent3c474bc2022-12-16 17:24:32 +01009485 public boolean isBluetoothVariableLatencyEnabled() {
9486 try {
9487 return getService().isBluetoothVariableLatencyEnabled();
9488 } catch (RemoteException e) {
9489 throw e.rethrowFromSystemServer();
9490 }
9491 }
9492
jiabin89f87ed2022-12-01 22:55:05 +00009493 //====================================================================
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009494 // Stream aliasing changed listener, getter for stream alias or independent streams
9495
9496 /**
9497 * manages the stream aliasing listeners and StreamAliasingDispatcherStub
9498 */
9499 private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr =
9500 new CallbackUtil.LazyListenerManager();
9501
9502
9503 final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub
9504 implements CallbackUtil.DispatcherStub {
9505
9506 @Override
9507 public void register(boolean register) {
9508 try {
9509 getService().registerStreamAliasingDispatcher(this, register);
9510 } catch (RemoteException e) {
9511 e.rethrowFromSystemServer();
9512 }
9513 }
9514
9515 @Override
9516 public void dispatchStreamAliasingChanged() {
9517 mStreamAliasingListenerMgr.callListeners((listener) -> listener.run());
9518 }
9519 }
9520
9521 /**
9522 * @hide
9523 * Adds a listener to be notified of changes to volume stream type aliasing.
9524 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
9525 * @param executor the Executor running the listener
9526 * @param onStreamAliasingChangedListener the listener to add for the aliasing changes
9527 */
9528 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009529 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009530 public void addOnStreamAliasingChangedListener(
9531 @NonNull @CallbackExecutor Executor executor,
9532 @NonNull Runnable onStreamAliasingChangedListener) {
9533 mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener,
9534 "addOnStreamAliasingChangedListener",
9535 () -> new StreamAliasingDispatcherStub());
9536 }
9537
9538 /**
9539 * @hide
9540 * Removes a previously added listener for changes to stream aliasing.
9541 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
9542 * @see #addOnStreamAliasingChangedListener(Executor, Runnable)
9543 * @param onStreamAliasingChangedListener the previously added listener of aliasing changes
9544 */
9545 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009546 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009547 public void removeOnStreamAliasingChangedListener(
9548 @NonNull Runnable onStreamAliasingChangedListener) {
9549 mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener,
9550 "removeOnStreamAliasingChangedListener");
9551 }
9552
9553 /**
9554 * @hide
9555 * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING,
9556 * volumes will be updated in case of a change.
9557 * @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING
9558 */
9559 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009560 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009561 public void setNotifAliasRingForTest(boolean isAliased) {
9562 final IAudioService service = getService();
9563 try {
9564 service.setNotifAliasRingForTest(isAliased);
9565 } catch (RemoteException e) {
9566 throw e.rethrowFromSystemServer();
9567 }
9568 }
9569
9570 /**
9571 * @hide
9572 * Return the list of independent stream types for volume control.
9573 * A stream type is considered independent when the volume changes of that type do not
9574 * affect any other independent volume control stream type.
9575 * An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}.
Jean-Michel Trivif8d51e22023-03-08 23:57:03 +00009576 * @return list of independent stream types, where each value can be one of
9577 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, {@link #STREAM_RING},
9578 * {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, {@link #STREAM_NOTIFICATION},
9579 * {@link #STREAM_DTMF} and {@link #STREAM_ACCESSIBILITY}.
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009580 */
9581 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009582 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009583 public @NonNull List<Integer> getIndependentStreamTypes() {
9584 final IAudioService service = getService();
9585 try {
9586 return service.getIndependentStreamTypes();
9587 } catch (RemoteException e) {
9588 throw e.rethrowFromSystemServer();
9589 }
9590 }
9591
9592 /**
9593 * @hide
9594 * Return the stream type that a given stream is aliased to.
9595 * A stream alias means that any change to the source stream will also be applied to the alias,
9596 * and vice-versa.
9597 * If a stream is independent (i.e. part of the stream types returned by
9598 * {@link #getIndependentStreamTypes()}), its alias is itself.
9599 * @param sourceStreamType the stream type to query for the alias.
9600 * @return the stream type the source type is aliased to.
9601 */
9602 @SystemApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009603 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009604 public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) {
9605 final IAudioService service = getService();
9606 try {
9607 return service.getStreamTypeAlias(sourceStreamType);
9608 } catch (RemoteException e) {
9609 throw e.rethrowFromSystemServer();
9610 }
9611 }
9612
9613 /**
9614 * @hide
9615 * Returns whether the system uses {@link AudioVolumeGroup} for volume control
9616 * @return true when volume control is performed through volume groups, false if it uses
9617 * stream types.
9618 */
9619 @TestApi
Jean-Michel Trivi10fd2d72023-02-13 18:06:36 +00009620 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
Jean-Michel Trivi5017dd82023-01-19 18:51:19 +00009621 public boolean isVolumeControlUsingVolumeGroups() {
9622 final IAudioService service = getService();
9623 try {
9624 return service.isVolumeControlUsingVolumeGroups();
9625 } catch (RemoteException e) {
9626 throw e.rethrowFromSystemServer();
9627 }
9628 }
9629
9630 //====================================================================
jiabin89f87ed2022-12-01 22:55:05 +00009631 // Mute await connection
9632
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08009633 private final Object mMuteAwaitConnectionListenerLock = new Object();
9634
9635 @GuardedBy("mMuteAwaitConnectionListenerLock")
9636 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
9637 mMuteAwaitConnectionListeners;
9638
9639 @GuardedBy("mMuteAwaitConnectionListenerLock")
9640 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
9641
9642 private final class MuteAwaitConnectionDispatcherStub
9643 extends IMuteAwaitConnectionCallback.Stub {
9644 public void register(boolean register) {
9645 try {
9646 getService().registerMuteAwaitConnectionDispatcher(this, register);
9647 } catch (RemoteException e) {
9648 throw e.rethrowFromSystemServer();
9649 }
9650 }
9651
9652 @Override
9653 @SuppressLint("GuardedBy") // lock applied inside callListeners method
9654 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
9655 int[] mutedUsages) {
9656 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
9657 mMuteAwaitConnectionListenerLock,
9658 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
9659 }
9660
9661 @Override
9662 @SuppressLint("GuardedBy") // lock applied inside callListeners method
9663 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
9664 int[] mutedUsages) {
9665 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
9666 mMuteAwaitConnectionListenerLock,
9667 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
9668 }
9669 }
9670
9671 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07009672 // Inner classes
9673 //--------------------
9674 /**
9675 * Helper class to handle the forwarding of native events to the appropriate listener
9676 * (potentially) handled in a different thread.
9677 */
9678 private class NativeEventHandlerDelegate {
9679 private final Handler mHandler;
9680
Paul McLean03346882015-05-12 15:36:56 -07009681 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07009682 Handler handler) {
9683 // find the looper for our new event handler
9684 Looper looper;
9685 if (handler != null) {
9686 looper = handler.getLooper();
9687 } else {
9688 // no given handler, use the looper the addListener call was called in
9689 looper = Looper.getMainLooper();
9690 }
9691
9692 // construct the event handler with this looper
9693 if (looper != null) {
9694 // implement the event handler delegate
9695 mHandler = new Handler(looper) {
9696 @Override
9697 public void handleMessage(Message msg) {
9698 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07009699 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07009700 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07009701 if (callback != null) {
9702 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07009703 }
9704 break;
Paul McLean03346882015-05-12 15:36:56 -07009705
9706 case MSG_DEVICES_DEVICES_REMOVED:
9707 if (callback != null) {
9708 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
9709 }
9710 break;
9711
Paul McLeane3383cc2015-05-08 11:41:20 -07009712 default:
9713 Log.e(TAG, "Unknown native event type: " + msg.what);
9714 break;
9715 }
9716 }
9717 };
9718 } else {
9719 mHandler = null;
9720 }
9721 }
9722
9723 Handler getHandler() {
9724 return mHandler;
9725 }
9726 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08009727}