blob: 8d96bb7ab2749125091b10fbb8ebc406b8c7d0ca [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
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080019import android.annotation.CallbackExecutor;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080020import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070021import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080022import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070023import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.annotation.SdkConstant;
26import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070027import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090028import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060029import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070030import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050031import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070032import android.app.PendingIntent;
Eric Laurent1c3408f2021-11-09 12:09:54 +010033import android.app.compat.CompatChanges;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080034import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070035import android.bluetooth.BluetoothDevice;
Patty46694212021-11-04 21:03:32 +080036import android.bluetooth.BluetoothLeAudioCodecConfig;
Eric Laurent1c3408f2021-11-09 12:09:54 +010037import android.compat.annotation.ChangeId;
38import android.compat.annotation.EnabledSince;
Artur Satayev53fe9662019-12-10 17:47:55 +000039import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070040import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070042import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080043import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080044import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070045import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080046import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070047import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070048import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020049import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080050import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070051import android.media.session.MediaController;
52import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070053import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070054import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070055import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070057import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Handler;
59import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080060import android.os.Looper;
61import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.os.RemoteException;
63import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050064import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010065import android.os.UserHandle;
Lais Andrade724d0cd2021-11-03 19:46:21 +000066import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080067import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070068import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080070import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070071import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080073import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020074import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080075
jiabinc0f49442018-01-05 10:23:50 -080076import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080077import java.lang.annotation.Retention;
78import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070079import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080080import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070081import java.util.Arrays;
Dorin Drimusdaeb6a92021-12-22 11:46:26 +010082import java.util.Collections;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080083import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070084import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090085import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080086import java.util.List;
jiabin39940752018-04-02 18:18:45 -070087import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070088import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090089import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070090import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080091import java.util.concurrent.Executor;
Eric Laurent78eef3a2021-11-09 16:10:42 +010092import java.util.concurrent.Executors;
Jean-Michel Trivi933bf142021-11-19 16:18:52 -080093import java.util.concurrent.TimeUnit;
Eric Laurent700e7342014-05-02 18:33:15 -070094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095/**
96 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060098@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099public class AudioManager {
100
Marco Nelissen29f16932015-04-17 09:50:56 -0700101 private Context mOriginalContext;
102 private Context mApplicationContext;
Joe Onorato86f67862010-11-05 18:57:34 -0700103 private long mVolumeKeyUpTime;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800104 private static final String TAG = "AudioManager";
105 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800106 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200107 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
108 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
jiabin0f3339c2021-07-09 11:50:07 -0700110 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 /**
113 * Broadcast intent, a hint for applications that audio is about to become
114 * 'noisy' due to a change in audio outputs. For example, this intent may
115 * be sent when a wired headset is unplugged, or when an A2DP audio
116 * sink is disconnected, and the audio system is about to automatically
117 * switch audio route to the speaker. Applications that are controlling
118 * audio streams may consider pausing, reducing volume or some other action
119 * on receipt of this intent so as not to surprise the user with audio
120 * from the speaker.
121 */
122 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
123 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
124
125 /**
126 * Sticky broadcast intent action indicating that the ringer mode has
127 * changed. Includes the new ringer mode.
128 *
129 * @see #EXTRA_RINGER_MODE
130 */
131 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
132 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
133
134 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500135 * @hide
136 * Sticky broadcast intent action indicating that the internal ringer mode has
137 * changed. Includes the new ringer mode.
138 *
139 * @see #EXTRA_RINGER_MODE
140 */
141 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
142 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
143 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
144
145 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 * The new ringer mode.
147 *
148 * @see #RINGER_MODE_CHANGED_ACTION
149 * @see #RINGER_MODE_NORMAL
150 * @see #RINGER_MODE_SILENT
151 * @see #RINGER_MODE_VIBRATE
152 */
153 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
154
155 /**
156 * Broadcast intent action indicating that the vibrate setting has
157 * changed. Includes the vibrate type and its new setting.
158 *
159 * @see #EXTRA_VIBRATE_TYPE
160 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700161 * @deprecated Applications should maintain their own vibrate policy based on
162 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 */
164 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500165 public static final String VIBRATE_SETTING_CHANGED_ACTION =
166 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
168 /**
169 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700170 * Includes the stream, the new volume and previous volumes.
171 * Notes:
172 * - for internal platform use only, do not make public,
173 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 *
175 * @see #EXTRA_VOLUME_STREAM_TYPE
176 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800177 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 */
179 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100180 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
182
183 /**
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800184 * @hide Broadcast intent when the volume for a particular stream type changes.
185 * Includes the stream, the new volume and previous volumes.
186 * Notes:
187 * - for internal platform use only, do not make public,
188 * - never used for "remote" volume changes
189 *
190 * @see #EXTRA_VOLUME_STREAM_TYPE
191 * @see #EXTRA_VOLUME_STREAM_VALUE
192 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
193 */
194 @SystemApi
195 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
196 @SuppressLint("ActionValue")
197 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
198
199 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400200 * @hide Broadcast intent when the devices for a particular stream type changes.
201 * Includes the stream, the new devices and previous devices.
202 * Notes:
203 * - for internal platform use only, do not make public,
204 * - never used for "remote" volume changes
205 *
206 * @see #EXTRA_VOLUME_STREAM_TYPE
207 * @see #EXTRA_VOLUME_STREAM_DEVICES
208 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
209 * @see #getDevicesForStream
210 */
211 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
212 public static final String STREAM_DEVICES_CHANGED_ACTION =
213 "android.media.STREAM_DEVICES_CHANGED_ACTION";
214
215 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800216 * @hide Broadcast intent when a stream mute state changes.
217 * Includes the stream that changed and the new mute state
218 *
219 * @see #EXTRA_VOLUME_STREAM_TYPE
220 * @see #EXTRA_STREAM_VOLUME_MUTED
221 */
222 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
223 public static final String STREAM_MUTE_CHANGED_ACTION =
224 "android.media.STREAM_MUTE_CHANGED_ACTION";
225
226 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500227 * @hide Broadcast intent when the master mute state changes.
228 * Includes the the new volume
229 *
230 * @see #EXTRA_MASTER_VOLUME_MUTED
231 */
232 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
233 public static final String MASTER_MUTE_CHANGED_ACTION =
234 "android.media.MASTER_MUTE_CHANGED_ACTION";
235
236 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 * The new vibrate setting for a particular type.
238 *
239 * @see #VIBRATE_SETTING_CHANGED_ACTION
240 * @see #EXTRA_VIBRATE_TYPE
241 * @see #VIBRATE_SETTING_ON
242 * @see #VIBRATE_SETTING_OFF
243 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700244 * @deprecated Applications should maintain their own vibrate policy based on
245 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 */
247 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
248
249 /**
250 * The vibrate type whose setting has changed.
251 *
252 * @see #VIBRATE_SETTING_CHANGED_ACTION
253 * @see #VIBRATE_TYPE_NOTIFICATION
254 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700255 * @deprecated Applications should maintain their own vibrate policy based on
256 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 */
258 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
259
260 /**
261 * @hide The stream type for the volume changed intent.
262 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800263 @SystemApi
264 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
266
267 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700268 * @hide
269 * The stream type alias for the volume changed intent.
270 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
271 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
272 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
273 * {@link #STREAM_MUSIC} on others (e.g. a television).
274 */
275 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
276 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
277
278 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 * @hide The volume associated with the stream for the volume changed intent.
280 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800281 @SystemApi
282 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 public static final String EXTRA_VOLUME_STREAM_VALUE =
284 "android.media.EXTRA_VOLUME_STREAM_VALUE";
285
Eric Laurent9ce379a2010-02-16 06:00:26 -0800286 /**
287 * @hide The previous volume associated with the stream for the volume changed intent.
288 */
289 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
290 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
291
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500292 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400293 * @hide The devices associated with the stream for the stream devices changed intent.
294 */
295 public static final String EXTRA_VOLUME_STREAM_DEVICES =
296 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
297
298 /**
299 * @hide The previous devices associated with the stream for the stream devices changed intent.
300 */
301 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
302 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
303
304 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500305 * @hide The new master volume mute state for the master mute changed intent.
306 * Value is boolean
307 */
308 public static final String EXTRA_MASTER_VOLUME_MUTED =
309 "android.media.EXTRA_MASTER_VOLUME_MUTED";
310
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700311 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800312 * @hide The new stream volume mute state for the stream mute changed intent.
313 * Value is boolean
314 */
315 public static final String EXTRA_STREAM_VOLUME_MUTED =
316 "android.media.EXTRA_STREAM_VOLUME_MUTED";
317
318 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700319 * Broadcast Action: Wired Headset plugged in or unplugged.
320 *
321 * You <em>cannot</em> receive this through components declared
322 * in manifests, only by explicitly registering for it with
323 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
324 * Context.registerReceiver()}.
325 *
326 * <p>The intent will have the following extra values:
327 * <ul>
328 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
329 * <li><em>name</em> - Headset type, human readable string </li>
330 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
331 * </ul>
332 * </ul>
333 */
334 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
335 public static final String ACTION_HEADSET_PLUG =
336 "android.intent.action.HEADSET_PLUG";
337
338 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200339 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700340 *
341 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
342 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
343 * <p>It can only be received by explicitly registering for it with
344 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
345 */
346 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
347 public static final String ACTION_HDMI_AUDIO_PLUG =
348 "android.media.action.HDMI_AUDIO_PLUG";
349
350 /**
351 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
352 * or unplugged.
353 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
354 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700355 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700356
357 /**
358 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
359 * supported by the HDMI device.
360 * The corresponding integer value is only available when the device is plugged in (as expressed
361 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
362 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700363 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700364
365 /**
366 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
367 * the connected HDMI device.
368 * The corresponding array of encoding values is only available when the device is plugged in
369 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
370 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
371 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
372 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700373 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700374
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700375 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700377 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700379 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700381 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700383 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700385 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700387 /** @hide Used to identify the volume of audio streams for phone calls when connected
388 * to bluetooth */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800389 @SystemApi
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700391 /** @hide Used to identify the volume of audio streams for enforced system sounds
392 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100393 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700394 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700395 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700396 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700397 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
398 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100399 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700400 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800401 /** Used to identify the volume of audio streams for accessibility prompts */
402 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000403 /** @hide Used to identify the volume of audio streams for virtual assistant */
404 @SystemApi
405 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
406 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 /** Number of audio streams */
409 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700410 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 */
Eric Laurenta553c252009-07-17 12:17:14 -0700412 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413
Paul McLeand6f87c82021-03-31 13:02:41 -0600414 /** @hide */
415 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
416 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
417 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
418 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
419
420 /** @hide */
421 @TestApi
422 public static final int[] getPublicStreamTypes() {
423 return PUBLIC_STREAM_TYPES;
424 }
425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 /**
427 * Increase the ringer volume.
428 *
429 * @see #adjustVolume(int, int)
430 * @see #adjustStreamVolume(int, int, int)
431 */
432 public static final int ADJUST_RAISE = 1;
433
434 /**
435 * Decrease the ringer volume.
436 *
437 * @see #adjustVolume(int, int)
438 * @see #adjustStreamVolume(int, int, int)
439 */
440 public static final int ADJUST_LOWER = -1;
441
442 /**
443 * Maintain the previous ringer volume. This may be useful when needing to
444 * show the volume toast without actually modifying the volume.
445 *
446 * @see #adjustVolume(int, int)
447 * @see #adjustStreamVolume(int, int, int)
448 */
449 public static final int ADJUST_SAME = 0;
450
RoboErik4197cb62015-01-21 15:45:32 -0800451 /**
452 * Mute the volume. Has no effect if the stream is already muted.
453 *
454 * @see #adjustVolume(int, int)
455 * @see #adjustStreamVolume(int, int, int)
456 */
457 public static final int ADJUST_MUTE = -100;
458
459 /**
460 * Unmute the volume. Has no effect if the stream is not muted.
461 *
462 * @see #adjustVolume(int, int)
463 * @see #adjustStreamVolume(int, int, int)
464 */
465 public static final int ADJUST_UNMUTE = 100;
466
467 /**
468 * Toggle the mute state. If muted the stream will be unmuted. If not muted
469 * the stream will be muted.
470 *
471 * @see #adjustVolume(int, int)
472 * @see #adjustStreamVolume(int, int, int)
473 */
474 public static final int ADJUST_TOGGLE_MUTE = 101;
475
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700476 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800477 @IntDef(flag = false, prefix = "ADJUST", value = {
478 ADJUST_RAISE,
479 ADJUST_LOWER,
480 ADJUST_SAME,
481 ADJUST_MUTE,
482 ADJUST_UNMUTE,
483 ADJUST_TOGGLE_MUTE }
484 )
485 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800486 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800487
488 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700489 public static final String adjustToString(int adj) {
490 switch (adj) {
491 case ADJUST_RAISE: return "ADJUST_RAISE";
492 case ADJUST_LOWER: return "ADJUST_LOWER";
493 case ADJUST_SAME: return "ADJUST_SAME";
494 case ADJUST_MUTE: return "ADJUST_MUTE";
495 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
496 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
497 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
498 }
499 }
500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 // Flags should be powers of 2!
502
503 /**
504 * Show a toast containing the current volume.
505 *
506 * @see #adjustStreamVolume(int, int, int)
507 * @see #adjustVolume(int, int)
508 * @see #setStreamVolume(int, int, int)
509 * @see #setRingerMode(int)
510 */
511 public static final int FLAG_SHOW_UI = 1 << 0;
512
513 /**
514 * Whether to include ringer modes as possible options when changing volume.
515 * For example, if true and volume level is 0 and the volume is adjusted
516 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
517 * vibrate mode.
518 * <p>
519 * By default this is on for the ring stream. If this flag is included,
520 * this behavior will be present regardless of the stream type being
521 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700522 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 * @see #adjustVolume(int, int)
524 * @see #adjustStreamVolume(int, int, int)
525 */
526 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
527
528 /**
529 * Whether to play a sound when changing the volume.
530 * <p>
531 * If this is given to {@link #adjustVolume(int, int)} or
532 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
533 * in some cases (for example, the decided stream type is not
534 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
535 * downward).
536 *
537 * @see #adjustStreamVolume(int, int, int)
538 * @see #adjustVolume(int, int)
539 * @see #setStreamVolume(int, int, int)
540 */
541 public static final int FLAG_PLAY_SOUND = 1 << 2;
542
543 /**
544 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
545 * changing volume).
546 */
547 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
548
549 /**
550 * Whether to vibrate if going into the vibrate ringer mode.
551 */
552 public static final int FLAG_VIBRATE = 1 << 4;
553
554 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700555 * Indicates to VolumePanel that the volume slider should be disabled as user
556 * cannot change the stream volume
557 * @hide
558 */
559 public static final int FLAG_FIXED_VOLUME = 1 << 5;
560
561 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700562 * Indicates the volume set/adjust call is for Bluetooth absolute volume
563 * @hide
564 */
Roopa Sattirajufb933242022-01-30 13:27:58 -0800565 @SystemApi
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700566 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
567
568 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400569 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
570 * @hide
571 */
572 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
573
574 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900575 * Indicates the volume call is for Hdmi Cec system audio volume
576 * @hide
577 */
578 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
579
580 /**
RoboErik3c45c292014-07-08 16:47:31 -0700581 * Indicates that this should only be handled if media is actively playing.
582 * @hide
583 */
584 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
585
586 /**
John Spurlock35134602014-07-24 18:10:48 -0400587 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
588 * @hide
589 */
590 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
591
592 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500593 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
594 * @hide
595 */
596 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
597
John Spurlockb94f2d62015-03-17 14:11:57 -0400598 /**
599 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900600 * This flag can be used in the places in order to denote (or check) that a volume adjustment
601 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400602 * @hide
603 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900604 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900605 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400606
Yan Han7d419822022-01-31 19:10:16 +0100607 /**
608 * Indicates that an absolute volume controller is notifying AudioService of a change in the
609 * volume or mute status of an external audio system.
610 * @hide
611 */
612 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
613
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900614 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100615 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200616 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100617 ENCODED_SURROUND_OUTPUT_AUTO,
618 ENCODED_SURROUND_OUTPUT_NEVER,
619 ENCODED_SURROUND_OUTPUT_ALWAYS,
620 ENCODED_SURROUND_OUTPUT_MANUAL
621 })
622 @Retention(RetentionPolicy.SOURCE)
623 public @interface EncodedSurroundOutputMode {}
624
625 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200626 * The mode for surround sound formats is unknown.
627 */
628 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
629
630 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100631 * The surround sound formats are available for use if they are detected. This is the default
632 * mode.
633 */
634 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
635
636 /**
637 * The surround sound formats are NEVER available, even if they are detected by the hardware.
638 * Those formats will not be reported.
639 */
640 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
641
642 /**
643 * The surround sound formats are ALWAYS available, even if they are not detected by the
644 * hardware. Those formats will be reported as part of the HDMI output capability.
645 * Applications are then free to use either PCM or encoded output.
646 */
647 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
648
649 /**
650 * Surround sound formats are available according to the choice of user, even if they are not
651 * detected by the hardware. Those formats will be reported as part of the HDMI output
652 * capability. Applications are then free to use either PCM or encoded output.
653 */
654 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
655
656 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900657 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900658 FLAG_SHOW_UI,
659 FLAG_ALLOW_RINGER_MODES,
660 FLAG_PLAY_SOUND,
661 FLAG_REMOVE_SOUND_AND_VIBRATE,
662 FLAG_VIBRATE,
663 FLAG_FIXED_VOLUME,
664 FLAG_BLUETOOTH_ABS_VOLUME,
665 FLAG_SHOW_SILENT_HINT,
666 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
667 FLAG_ACTIVE_MEDIA_ONLY,
668 FLAG_SHOW_UI_WARNINGS,
669 FLAG_SHOW_VIBRATE_HINT,
670 FLAG_FROM_KEY,
Yan Han7d419822022-01-31 19:10:16 +0100671 FLAG_ABSOLUTE_VOLUME,
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900672 })
673 @Retention(RetentionPolicy.SOURCE)
674 public @interface Flags {}
675
Hyundo Moonca0080d2018-12-26 16:16:55 +0900676 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
677 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
678
679 static {
680 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
681 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
682 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
683 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
684 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
685 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
686 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
687 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
688 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
689 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
690 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
691 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
692 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
Yan Han7d419822022-01-31 19:10:16 +0100693 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
Hyundo Moonca0080d2018-12-26 16:16:55 +0900694 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500695
696 /** @hide */
697 public static String flagsToString(int flags) {
698 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900699 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
700 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500701 if ((flags & flag) != 0) {
702 if (sb.length() > 0) {
703 sb.append(',');
704 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900705 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500706 flags &= ~flag;
707 }
708 }
709 if (flags != 0) {
710 if (sb.length() > 0) {
711 sb.append(',');
712 }
713 sb.append(flags);
714 }
715 return sb.toString();
716 }
717
718 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 * Ringer mode that will be silent and will not vibrate. (This overrides the
720 * vibrate setting.)
721 *
722 * @see #setRingerMode(int)
723 * @see #getRingerMode()
724 */
725 public static final int RINGER_MODE_SILENT = 0;
726
727 /**
728 * Ringer mode that will be silent and will vibrate. (This will cause the
729 * phone ringer to always vibrate, but the notification vibrate to only
730 * vibrate if set.)
731 *
732 * @see #setRingerMode(int)
733 * @see #getRingerMode()
734 */
735 public static final int RINGER_MODE_VIBRATE = 1;
736
737 /**
738 * Ringer mode that may be audible and may vibrate. It will be audible if
739 * the volume before changing out of this mode was audible. It will vibrate
740 * if the vibrate setting is on.
741 *
742 * @see #setRingerMode(int)
743 * @see #getRingerMode()
744 */
745 public static final int RINGER_MODE_NORMAL = 2;
746
John Spurlock97559372014-10-24 16:27:36 -0400747 /**
748 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
749 * @hide
750 */
751 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 /**
754 * Vibrate type that corresponds to the ringer.
755 *
756 * @see #setVibrateSetting(int, int)
757 * @see #getVibrateSetting(int)
758 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700759 * @deprecated Applications should maintain their own vibrate policy based on
760 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 */
762 public static final int VIBRATE_TYPE_RINGER = 0;
763
764 /**
765 * Vibrate type that corresponds to notifications.
766 *
767 * @see #setVibrateSetting(int, int)
768 * @see #getVibrateSetting(int)
769 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700770 * @deprecated Applications should maintain their own vibrate policy based on
771 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 */
773 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
774
775 /**
776 * Vibrate setting that suggests to never vibrate.
777 *
778 * @see #setVibrateSetting(int, int)
779 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700780 * @deprecated Applications should maintain their own vibrate policy based on
781 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 */
783 public static final int VIBRATE_SETTING_OFF = 0;
784
785 /**
786 * Vibrate setting that suggests to vibrate when possible.
787 *
788 * @see #setVibrateSetting(int, int)
789 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700790 * @deprecated Applications should maintain their own vibrate policy based on
791 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 */
793 public static final int VIBRATE_SETTING_ON = 1;
794
795 /**
796 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
797 * mode.
798 *
799 * @see #setVibrateSetting(int, int)
800 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700801 * @deprecated Applications should maintain their own vibrate policy based on
802 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 */
804 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
805
806 /**
807 * Suggests using the default stream type. This may not be used in all
808 * places a stream type is needed.
809 */
810 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
811
812 private static IAudioService sService;
813
814 /**
815 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800816 * For test purposes only, will throw NPE with some methods that require a Context.
817 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000818 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800819 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800820 }
821
822 /**
823 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100825 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700827 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
Marco Nelissen29f16932015-04-17 09:50:56 -0700830 private Context getContext() {
831 if (mApplicationContext == null) {
832 setContext(mOriginalContext);
833 }
834 if (mApplicationContext != null) {
835 return mApplicationContext;
836 }
837 return mOriginalContext;
838 }
839
840 private void setContext(Context context) {
841 mApplicationContext = context.getApplicationContext();
842 if (mApplicationContext != null) {
843 mOriginalContext = null;
844 } else {
845 mOriginalContext = context;
846 }
jiabin0f3339c2021-07-09 11:50:07 -0700847 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700848 }
849
Mathew Inwood31a792a2018-08-17 08:54:26 +0100850 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700851 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 {
853 if (sService != null) {
854 return sService;
855 }
856 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
857 sService = IAudioService.Stub.asInterface(b);
858 return sService;
859 }
860
861 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700862 * Sends a simulated key event for a media button.
863 * To simulate a key press, you must first send a KeyEvent built with a
864 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
865 * action.
866 * <p>The key event will be sent to the current media key event consumer which registered with
867 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
868 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
869 * {@link KeyEvent#KEYCODE_MUTE},
870 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
871 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
872 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
873 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
874 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
875 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
876 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
877 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
878 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
879 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
880 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
881 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
882 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700883 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700884 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700885 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700886 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700887 }
888
889 /**
890 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700891 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800892 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700893 /*
894 * If the user hits another key within the play sound delay, then
895 * cancel the sound
896 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800897 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700898 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
899 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500900 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700901 /*
902 * The user has hit another key during the delay (e.g., 300ms)
903 * since the last volume key up, so cancel any sounds.
904 */
John Spurlockee5ad722015-03-03 16:17:21 -0500905 adjustSuggestedStreamVolume(ADJUST_SAME,
906 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700907 }
908 }
909
910 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700911 * Indicates if the device implements a fixed volume policy.
912 * <p>Some devices may not have volume control and may operate at a fixed volume,
913 * and may not enable muting or changing the volume of audio streams.
914 * This method will return true on such devices.
915 * <p>The following APIs have no effect when volume is fixed:
916 * <ul>
917 * <li> {@link #adjustVolume(int, int)}
918 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
919 * <li> {@link #adjustStreamVolume(int, int, int)}
920 * <li> {@link #setStreamVolume(int, int, int)}
921 * <li> {@link #setRingerMode(int)}
922 * <li> {@link #setStreamSolo(int, boolean)}
923 * <li> {@link #setStreamMute(int, boolean)}
924 * </ul>
925 */
926 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700927 boolean res = false;
928 try {
929 res = getService().isVolumeFixed();
930 } catch (RemoteException e) {
931 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700932 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700933 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700934 }
935
936 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700938 * <p>
939 * This method should only be used by applications that replace the platform-wide
940 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700941 * <p>This method has no effect if the device implements a fixed volume policy
942 * as indicated by {@link #isVolumeFixed()}.
943 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
944 * unless the app has been granted Do Not Disturb Access.
945 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 *
947 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800948 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
949 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 * @param direction The direction to adjust the volume. One of
951 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
952 * {@link #ADJUST_SAME}.
953 * @param flags One or more flags.
954 * @see #adjustVolume(int, int)
955 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700956 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
957 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 */
959 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700960 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 try {
John Wu4f7e5102021-06-22 17:29:11 +0000962 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
963 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700965 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 }
967 }
968
969 /**
970 * Adjusts the volume of the most relevant stream. For example, if a call is
971 * active, it will have the highest priority regardless of if the in-call
972 * screen is showing. Another example, if music is playing in the background
973 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700974 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800975 * This method should only be used by applications that replace the
976 * platform-wide management of audio settings or the main telephony
977 * application.
978 * <p>
979 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700980 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800981 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800983 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
984 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
985 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 * @param flags One or more flags.
987 * @see #adjustSuggestedStreamVolume(int, int, int)
988 * @see #adjustStreamVolume(int, int, int)
989 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700990 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 */
992 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700993 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500994 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
997 /**
998 * Adjusts the volume of the most relevant stream, or the given fallback
999 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001000 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001001 * This method should only be used by applications that replace the
1002 * platform-wide management of audio settings or the main telephony
1003 * application.
1004 * <p>
1005 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001006 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001007 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001009 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1010 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1011 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001013 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1014 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 * @param flags One or more flags.
1016 * @see #adjustVolume(int, int)
1017 * @see #adjustStreamVolume(int, int, int)
1018 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001019 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 */
1021 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001022 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001023 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001024 }
1025
John Spurlockee5ad722015-03-03 16:17:21 -05001026 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001027 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -07001028 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001029 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001030 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001031 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001032 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001033 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001034 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001035 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
1037 }
1038
1039 /**
1040 * Returns the current ringtone mode.
1041 *
1042 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1043 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1044 * @see #setRingerMode(int)
1045 */
1046 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001047 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001049 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001051 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053 }
1054
1055 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001056 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1057 *
1058 * @return true if the incoming phone call ringtone is configured to gradually increase its
1059 * volume, false otherwise.
1060 */
1061 public boolean isRampingRingerEnabled() {
1062 return Settings.System.getInt(getContext().getContentResolver(),
1063 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1064 }
1065
1066 /**
1067 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1068 *
1069 * @see #isRampingRingerEnabled()
1070 * @hide
1071 */
1072 @TestApi
1073 public void setRampingRingerEnabled(boolean enabled) {
1074 Settings.System.putInt(getContext().getContentResolver(),
1075 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1076 }
1077
1078 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001079 * Checks valid ringer mode values.
1080 *
1081 * @return true if the ringer mode indicated is valid, false otherwise.
1082 *
1083 * @see #setRingerMode(int)
1084 * @hide
1085 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001086 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001087 public static boolean isValidRingerMode(int ringerMode) {
1088 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1089 return false;
1090 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001091 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001092 try {
1093 return service.isValidRingerMode(ringerMode);
1094 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001095 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001096 }
Eric Laurent72668b22011-07-19 16:04:27 -07001097 }
1098
1099 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 * Returns the maximum volume index for a particular stream.
1101 *
1102 * @param streamType The stream type whose maximum volume index is returned.
1103 * @return The maximum valid volume index for the stream.
1104 * @see #getStreamVolume(int)
1105 */
1106 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001107 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001109 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001111 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
1113 }
1114
1115 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001116 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001117 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1118 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1119 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1120 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1121 * @return The minimum valid volume index for the stream.
1122 * @see #getStreamVolume(int)
1123 */
1124 public int getStreamMinVolume(int streamType) {
1125 if (!isPublicStreamType(streamType)) {
1126 throw new IllegalArgumentException("Invalid stream type " + streamType);
1127 }
1128 return getStreamMinVolumeInt(streamType);
1129 }
1130
1131 /**
1132 * @hide
1133 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001134 * @param streamType The stream type whose minimum volume index is returned.
1135 * @return The minimum valid volume index for the stream.
1136 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001137 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001138 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001139 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001140 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001141 try {
1142 return service.getStreamMinVolume(streamType);
1143 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001144 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001145 }
1146 }
1147
1148 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 * Returns the current volume index for a particular stream.
1150 *
1151 * @param streamType The stream type whose volume index is returned.
1152 * @return The current volume index for the stream.
1153 * @see #getStreamMaxVolume(int)
1154 * @see #setStreamVolume(int, int, int)
1155 */
1156 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001157 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001159 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001161 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163 }
1164
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001165 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1166 private static final float VOLUME_MIN_DB = -758.0f;
1167
1168 /** @hide */
1169 @IntDef(flag = false, prefix = "STREAM", value = {
1170 STREAM_VOICE_CALL,
1171 STREAM_SYSTEM,
1172 STREAM_RING,
1173 STREAM_MUSIC,
1174 STREAM_ALARM,
1175 STREAM_NOTIFICATION,
1176 STREAM_DTMF,
1177 STREAM_ACCESSIBILITY }
1178 )
1179 @Retention(RetentionPolicy.SOURCE)
1180 public @interface PublicStreamTypes {}
1181
1182 /**
1183 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1184 * the given type of audio output device.
1185 * @param streamType stream type for which the volume is queried.
1186 * @param index the volume index for which the volume is queried. The index value must be
1187 * between the minimum and maximum index values for the given stream type (see
1188 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1189 * @param deviceType the type of audio output device for which volume is queried.
1190 * @return a volume expressed in dB.
1191 * A negative value indicates the audio signal is attenuated. A typical maximum value
1192 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1193 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1194 */
1195 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1196 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1197 if (!isPublicStreamType(streamType)) {
1198 throw new IllegalArgumentException("Invalid stream type " + streamType);
1199 }
1200 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1201 throw new IllegalArgumentException("Invalid stream volume index " + index);
1202 }
1203 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1204 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1205 }
1206 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1207 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1208 if (gain <= VOLUME_MIN_DB) {
1209 return Float.NEGATIVE_INFINITY;
1210 } else {
1211 return gain;
1212 }
1213 }
1214
Jean-Michel Trivi7ec3e242022-09-28 21:46:51 +00001215 /**
1216 * @hide
1217 * Checks whether a stream type is part of the public SDK
1218 * @param streamType
1219 * @return true if the stream type is available in SDK
1220 */
1221 public static boolean isPublicStreamType(int streamType) {
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001222 switch (streamType) {
1223 case STREAM_VOICE_CALL:
1224 case STREAM_SYSTEM:
1225 case STREAM_RING:
1226 case STREAM_MUSIC:
1227 case STREAM_ALARM:
1228 case STREAM_NOTIFICATION:
1229 case STREAM_DTMF:
1230 case STREAM_ACCESSIBILITY:
1231 return true;
1232 default:
1233 return false;
1234 }
1235 }
1236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001238 * Get last audible volume before stream was muted.
1239 *
1240 * @hide
1241 */
wescandee178f8f2021-10-19 20:15:09 +02001242 @SystemApi
1243 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001244 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001245 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001246 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001247 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001248 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001249 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001250 }
1251 }
1252
1253 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001254 * Get the stream type whose volume is driving the UI sounds volume.
1255 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001256 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001257 * @hide
1258 */
John Spurlockee5ad722015-03-03 16:17:21 -05001259 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001260 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001261 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001262 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001263 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001264 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001265 }
1266 }
1267
1268 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 * Sets the ringer mode.
1270 * <p>
1271 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1272 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1273 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001274 * <p>This method has no effect if the device implements a fixed volume policy
1275 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001276 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1277 * unless the app has been granted Do Not Disturb Access.
1278 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1280 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1281 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001282 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 */
1284 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001285 if (!isValidRingerMode(ringerMode)) {
1286 return;
1287 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001288 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001290 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001292 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 }
1294 }
1295
1296 /**
1297 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001298 * <p>This method has no effect if the device implements a fixed volume policy
1299 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001300 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1301 * the app has been granted Do Not Disturb Access.
1302 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 * @param streamType The stream whose volume index should be set.
1304 * @param index The volume index to set. See
1305 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1306 * @param flags One or more flags.
1307 * @see #getStreamMaxVolume(int)
1308 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001309 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001310 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1311 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 */
1313 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001314 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 try {
John Wu4f7e5102021-06-22 17:29:11 +00001316 service.setStreamVolumeWithAttribution(streamType, index, flags,
1317 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001319 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 }
1321 }
1322
1323 /**
François Gaffie9c362102018-09-21 17:43:52 +02001324 * Sets the volume index for a particular {@link AudioAttributes}.
1325 * @param attr The {@link AudioAttributes} whose volume index should be set.
1326 * @param index The volume index to set. See
1327 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1328 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1329 * @param flags One or more flags.
1330 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1331 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1332 * @see #isVolumeFixed()
1333 * @hide
1334 */
1335 @SystemApi
1336 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1337 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1338 Preconditions.checkNotNull(attr, "attr must not be null");
1339 final IAudioService service = getService();
1340 try {
1341 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001342 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001343 } catch (RemoteException e) {
1344 throw e.rethrowFromSystemServer();
1345 }
1346 }
1347
1348 /**
1349 * Returns the current volume index for a particular {@link AudioAttributes}.
1350 *
1351 * @param attr The {@link AudioAttributes} whose volume index is returned.
1352 * @return The current volume index for the stream.
1353 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1354 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1355 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1356 * @hide
1357 */
1358 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001359 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001360 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1361 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1362 Preconditions.checkNotNull(attr, "attr must not be null");
1363 final IAudioService service = getService();
1364 try {
1365 return service.getVolumeIndexForAttributes(attr);
1366 } catch (RemoteException e) {
1367 throw e.rethrowFromSystemServer();
1368 }
1369 }
1370
1371 /**
1372 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1373 *
1374 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1375 * @return The maximum valid volume index for the {@link AudioAttributes}.
1376 * @see #getVolumeIndexForAttributes(AudioAttributes)
1377 * @hide
1378 */
1379 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001380 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001381 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1382 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1383 Preconditions.checkNotNull(attr, "attr must not be null");
1384 final IAudioService service = getService();
1385 try {
1386 return service.getMaxVolumeIndexForAttributes(attr);
1387 } catch (RemoteException e) {
1388 throw e.rethrowFromSystemServer();
1389 }
1390 }
1391
1392 /**
1393 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1394 *
1395 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1396 * @return The minimum valid volume index for the {@link AudioAttributes}.
1397 * @see #getVolumeIndexForAttributes(AudioAttributes)
1398 * @hide
1399 */
1400 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001401 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001402 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1403 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1404 Preconditions.checkNotNull(attr, "attr must not be null");
1405 final IAudioService service = getService();
1406 try {
1407 return service.getMinVolumeIndexForAttributes(attr);
1408 } catch (RemoteException e) {
1409 throw e.rethrowFromSystemServer();
1410 }
1411 }
1412
1413 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001414 * Set the system usages to be supported on this device.
1415 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1416 * @hide
1417 */
1418 @SystemApi
1419 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1420 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1421 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1422 final IAudioService service = getService();
1423 try {
1424 service.setSupportedSystemUsages(systemUsages);
1425 } catch (RemoteException e) {
1426 throw e.rethrowFromSystemServer();
1427 }
1428 }
1429
1430 /**
1431 * Get the system usages supported on this device.
1432 * @return array of supported system usages {@link AttributeSystemUsage}
1433 * @hide
1434 */
1435 @SystemApi
1436 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1437 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1438 final IAudioService service = getService();
1439 try {
1440 return service.getSupportedSystemUsages();
1441 } catch (RemoteException e) {
1442 throw e.rethrowFromSystemServer();
1443 }
1444 }
1445
1446 /**
RoboErik4197cb62015-01-21 15:45:32 -08001447 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001449 * Do not use. This method has been deprecated and is now a no-op.
1450 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 *
1452 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001453 * @param state The required solo state: true for solo ON, false for solo
1454 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001455 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001456 * @deprecated Do not use. If you need exclusive audio playback use
1457 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 */
RoboErik4197cb62015-01-21 15:45:32 -08001459 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001461 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 }
1463
1464 /**
1465 * Mute or unmute an audio stream.
1466 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001467 * This method should only be used by applications that replace the
1468 * platform-wide management of audio settings or the main telephony
1469 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001471 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001472 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001473 * <p>
1474 * This method was deprecated in API level 22. Prior to API level 22 this
1475 * method had significantly different behavior and should be used carefully.
1476 * The following applies only to pre-22 platforms:
1477 * <ul>
1478 * <li>The mute command is protected against client process death: if a
1479 * process with an active mute request on a stream dies, this stream will be
1480 * unmuted automatically.</li>
1481 * <li>The mute requests for a given stream are cumulative: the AudioManager
1482 * can receive several mute requests from one or more clients and the stream
1483 * will be unmuted only when the same number of unmute requests are
1484 * received.</li>
1485 * <li>For a better user experience, applications MUST unmute a muted stream
1486 * in onPause() and mute is again in onResume() if appropriate.</li>
1487 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 *
1489 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001490 * @param state The required mute state: true for mute ON, false for mute
1491 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001492 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001493 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1494 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 */
RoboErik4197cb62015-01-21 15:45:32 -08001496 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001498 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1499 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1500 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1501 adjustSuggestedStreamVolume(direction, streamType, 0);
1502 } else {
1503 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 }
1505 }
1506
1507 /**
RoboErik4197cb62015-01-21 15:45:32 -08001508 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001509 *
RoboErik4197cb62015-01-21 15:45:32 -08001510 * @param streamType The stream to get mute state for.
1511 * @return The mute state for the given stream.
1512 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001513 */
1514 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001515 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001516 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001517 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001518 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001519 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001520 }
1521 }
1522
1523 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001524 * get master mute state.
1525 *
1526 * @hide
1527 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001528 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001529 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001530 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001531 try {
1532 return service.isMasterMute();
1533 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001534 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001535 }
1536 }
1537
1538 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001539 * forces the stream controlled by hard volume keys
1540 * specifying streamType == -1 releases control to the
1541 * logic.
1542 *
1543 * @hide
1544 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001545 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001546 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001547 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001548 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001549 try {
1550 service.forceVolumeControlStream(streamType, mICallBack);
1551 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001552 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001553 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001554 }
1555
1556 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 * Returns whether a particular type should vibrate according to user
1558 * settings and the current ringer mode.
1559 * <p>
1560 * This shouldn't be needed by most clients that use notifications to
1561 * vibrate. The notification manager will not vibrate if the policy doesn't
1562 * allow it, so the client should always set a vibrate pattern and let the
1563 * notification manager control whether or not to actually vibrate.
1564 *
1565 * @param vibrateType The type of vibrate. One of
1566 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1567 * {@link #VIBRATE_TYPE_RINGER}.
1568 * @return Whether the type should vibrate at the instant this method is
1569 * called.
1570 * @see #setVibrateSetting(int, int)
1571 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001572 * @deprecated Applications should maintain their own vibrate policy based on
1573 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 */
1575 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001576 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 try {
1578 return service.shouldVibrate(vibrateType);
1579 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001580 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 }
1582 }
1583
1584 /**
1585 * Returns whether the user's vibrate setting for a vibrate type.
1586 * <p>
1587 * This shouldn't be needed by most clients that want to vibrate, instead
1588 * see {@link #shouldVibrate(int)}.
1589 *
1590 * @param vibrateType The type of vibrate. One of
1591 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1592 * {@link #VIBRATE_TYPE_RINGER}.
1593 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1594 * {@link #VIBRATE_SETTING_OFF}, or
1595 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1596 * @see #setVibrateSetting(int, int)
1597 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001598 * @deprecated Applications should maintain their own vibrate policy based on
1599 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 */
1601 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001602 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 try {
1604 return service.getVibrateSetting(vibrateType);
1605 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001606 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608 }
1609
1610 /**
1611 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001612 * <p>
1613 * This method should only be used by applications that replace the platform-wide
1614 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 *
1616 * @param vibrateType The type of vibrate. One of
1617 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1618 * {@link #VIBRATE_TYPE_RINGER}.
1619 * @param vibrateSetting The vibrate setting, one of
1620 * {@link #VIBRATE_SETTING_ON},
1621 * {@link #VIBRATE_SETTING_OFF}, or
1622 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1623 * @see #getVibrateSetting(int)
1624 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001625 * @deprecated Applications should maintain their own vibrate policy based on
1626 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 */
1628 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001629 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 try {
1631 service.setVibrateSetting(vibrateType, vibrateSetting);
1632 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001633 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
1635 }
1636
1637 /**
1638 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001639 * <p>
1640 * This method should only be used by applications that replace the platform-wide
1641 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 *
1643 * @param on set <var>true</var> to turn on speakerphone;
1644 * <var>false</var> to turn it off
1645 */
1646 public void setSpeakerphoneOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001647 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001648 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001649 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001650 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001651 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 }
1654
1655 /**
1656 * Checks whether the speakerphone is on or off.
1657 *
1658 * @return true if speakerphone is on, false if it's off
1659 */
1660 public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001661 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001662 try {
1663 return service.isSpeakerphoneOn();
1664 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001665 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 }
1668
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001669 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001670 * 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 -07001671 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001672 *
1673 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1674 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001675 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001676 * <ul>
1677 * <li> for each track independently, see
1678 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1679 * <li> application-wide at runtime, with this method </li>
1680 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1681 * manifest. </li>
1682 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001683 * The most restrictive policy is always applied.
1684 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001685 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001686 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001687 *
1688 * @param capturePolicy one of
1689 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1690 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1691 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001692 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001693 */
1694 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001695 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001696 final IAudioService service = getService();
1697 try {
1698 int result = service.setAllowedCapturePolicy(capturePolicy);
1699 if (result != AudioSystem.AUDIO_STATUS_OK) {
1700 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1701 return;
1702 }
1703 } catch (RemoteException e) {
1704 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001705 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001706 }
1707
Kevin Rocard019f60d2019-04-09 16:25:26 -07001708 /**
1709 * Return the capture policy.
1710 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1711 * the default if it was not called.
1712 */
1713 @AudioAttributes.CapturePolicy
1714 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001715 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1716 try {
1717 result = getService().getAllowedCapturePolicy();
1718 } catch (RemoteException e) {
1719 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1720 }
1721 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001722 }
1723
Eric Laurent3def1ee2010-03-17 23:26:26 -07001724 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001725 // Audio Product Strategy routing
1726
1727 /**
1728 * @hide
1729 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1730 * this audio strategy. Note that the device may not be available at the time the preferred
1731 * device is set, but it will be used once made available.
1732 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1733 * this preference for this strategy.</p>
1734 * @param strategy the audio strategy whose routing will be affected
1735 * @param device the audio device to route to when available
1736 * @return true if the operation was successful, false otherwise
1737 */
1738 @SystemApi
1739 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1740 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001741 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001742 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001743 }
1744
1745 /**
1746 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001747 * Removes the preferred audio device(s) previously set with
1748 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1749 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001750 * @param strategy the audio strategy whose routing will be affected
1751 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1752 * device set for example)
1753 */
1754 @SystemApi
1755 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1756 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1757 Objects.requireNonNull(strategy);
1758 try {
1759 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001760 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001761 return status == AudioSystem.SUCCESS;
1762 } catch (RemoteException e) {
1763 throw e.rethrowFromSystemServer();
1764 }
1765 }
1766
1767 /**
1768 * @hide
1769 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001770 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1771 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1772 * @param strategy the strategy to query
1773 * @return the preferred device for that strategy, if multiple devices are set as preferred
1774 * devices, the first one in the list will be returned. Null will be returned if none was
1775 * ever set or if the strategy is invalid
1776 */
1777 @SystemApi
1778 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1779 @Nullable
1780 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1781 @NonNull AudioProductStrategy strategy) {
1782 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1783 return devices.isEmpty() ? null : devices.get(0);
1784 }
1785
1786 /**
1787 * @hide
1788 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1789 * this audio strategy. Note that the devices may not be available at the time the preferred
1790 * devices is set, but it will be used once made available.
1791 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1792 * this preference for this strategy.</p>
1793 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1794 * devices used simultaneously to output the same audio signal.
1795 * @param strategy the audio strategy whose routing will be affected
1796 * @param devices a non-empty list of the audio devices to route to when available
1797 * @return true if the operation was successful, false otherwise
1798 */
1799 @SystemApi
1800 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1801 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1802 @NonNull List<AudioDeviceAttributes> devices) {
1803 Objects.requireNonNull(strategy);
1804 Objects.requireNonNull(devices);
1805 if (devices.isEmpty()) {
1806 throw new IllegalArgumentException(
1807 "Tried to set preferred devices for strategy with a empty list");
1808 }
1809 for (AudioDeviceAttributes device : devices) {
1810 Objects.requireNonNull(device);
1811 }
1812 try {
1813 final int status =
1814 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1815 return status == AudioSystem.SUCCESS;
1816 } catch (RemoteException e) {
1817 throw e.rethrowFromSystemServer();
1818 }
1819 }
1820
1821 /**
1822 * @hide
1823 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001824 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001825 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001826 * @param strategy the strategy to query
1827 * @return the preferred device for that strategy, or null if none was ever set or if the
1828 * strategy is invalid
1829 */
1830 @SystemApi
1831 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001832 @NonNull
1833 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001834 @NonNull AudioProductStrategy strategy) {
1835 Objects.requireNonNull(strategy);
1836 try {
jiabinf40141d2020-08-07 17:27:48 -07001837 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001838 } catch (RemoteException e) {
1839 throw e.rethrowFromSystemServer();
1840 }
1841 }
1842
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001843 /**
1844 * @hide
1845 * Interface to be notified of changes in the preferred audio device set for a given audio
1846 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001847 * <p>Note that this listener will only be invoked whenever
1848 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001849 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001850 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1851 * preferred device. It will not be invoked directly after registration with
1852 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1853 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001854 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001855 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1856 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001857 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001858 */
1859 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001860 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001861 public interface OnPreferredDeviceForStrategyChangedListener {
1862 /**
1863 * Called on the listener to indicate that the preferred audio device for the given
1864 * strategy has changed.
1865 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1866 * @param device <code>null</code> if the preferred device was removed, or the newly set
1867 * preferred audio device
1868 */
1869 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001870 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001871 }
1872
1873 /**
1874 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001875 * Interface to be notified of changes in the preferred audio devices set for a given audio
1876 * strategy.
1877 * <p>Note that this listener will only be invoked whenever
1878 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1879 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1880 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1881 * preferred device(s). It will not be invoked directly after registration with
1882 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1883 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1884 * to indicate which strategies had preferred devices at the time of registration.</p>
1885 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1886 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1887 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1888 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
1889 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1890 */
1891 @SystemApi
1892 public interface OnPreferredDevicesForStrategyChangedListener {
1893 /**
1894 * Called on the listener to indicate that the preferred audio devices for the given
1895 * strategy has changed.
1896 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1897 * @param devices a list of newly set preferred audio devices
1898 */
1899 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1900 @NonNull List<AudioDeviceAttributes> devices);
1901 }
1902
1903 /**
1904 * @hide
1905 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1906 * @param executor
1907 * @param listener
1908 * @throws SecurityException if the caller doesn't hold the required permission
1909 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1910 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1911 */
1912 @SystemApi
1913 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1914 @Deprecated
1915 public void addOnPreferredDeviceForStrategyChangedListener(
1916 @NonNull @CallbackExecutor Executor executor,
1917 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
1918 throws SecurityException {
1919 // No-op, the method is deprecated.
1920 }
1921
1922 /**
1923 * @hide
1924 * Removes a previously added listener of changes to the strategy-preferred audio device.
1925 * @param listener
1926 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
1927 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1928 */
1929 @SystemApi
1930 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1931 @Deprecated
1932 public void removeOnPreferredDeviceForStrategyChangedListener(
1933 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
1934 // No-op, the method is deprecated.
1935 }
1936
1937 /**
1938 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001939 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1940 * @param executor
1941 * @param listener
1942 * @throws SecurityException if the caller doesn't hold the required permission
1943 */
1944 @SystemApi
1945 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001946 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001947 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07001948 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001949 throws SecurityException {
1950 Objects.requireNonNull(executor);
1951 Objects.requireNonNull(listener);
1952 synchronized (mPrefDevListenerLock) {
1953 if (hasPrefDevListener(listener)) {
1954 throw new IllegalArgumentException(
jiabinf40141d2020-08-07 17:27:48 -07001955 "attempt to call addOnPreferredDevicesForStrategyChangedListener() "
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001956 + "on a previously registered listener");
1957 }
1958 // lazy initialization of the list of strategy-preferred device listener
1959 if (mPrefDevListeners == null) {
1960 mPrefDevListeners = new ArrayList<>();
1961 }
1962 final int oldCbCount = mPrefDevListeners.size();
1963 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor));
1964 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) {
1965 // register binder for callbacks
1966 if (mPrefDevDispatcherStub == null) {
jiabinf40141d2020-08-07 17:27:48 -07001967 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001968 }
1969 try {
jiabinf40141d2020-08-07 17:27:48 -07001970 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001971 } catch (RemoteException e) {
1972 throw e.rethrowFromSystemServer();
1973 }
1974 }
1975 }
1976 }
1977
1978 /**
1979 * @hide
1980 * Removes a previously added listener of changes to the strategy-preferred audio device.
1981 * @param listener
1982 */
1983 @SystemApi
1984 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001985 public void removeOnPreferredDevicesForStrategyChangedListener(
1986 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001987 Objects.requireNonNull(listener);
1988 synchronized (mPrefDevListenerLock) {
1989 if (!removePrefDevListener(listener)) {
1990 throw new IllegalArgumentException(
1991 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() "
1992 + "on an unregistered listener");
1993 }
1994 if (mPrefDevListeners.size() == 0) {
1995 // unregister binder for callbacks
1996 try {
jiabinf40141d2020-08-07 17:27:48 -07001997 getService().unregisterStrategyPreferredDevicesDispatcher(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001998 mPrefDevDispatcherStub);
1999 } catch (RemoteException e) {
2000 throw e.rethrowFromSystemServer();
2001 } finally {
2002 mPrefDevDispatcherStub = null;
2003 mPrefDevListeners = null;
2004 }
2005 }
2006 }
2007 }
2008
2009
2010 private final Object mPrefDevListenerLock = new Object();
2011 /**
2012 * List of listeners for preferred device for strategy and their associated Executor.
2013 * List is lazy-initialized on first registration
2014 */
2015 @GuardedBy("mPrefDevListenerLock")
2016 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners;
2017
2018 private static class PrefDevListenerInfo {
jiabinf40141d2020-08-07 17:27:48 -07002019 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002020 final @NonNull Executor mExecutor;
jiabinf40141d2020-08-07 17:27:48 -07002021 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002022 mListener = listener;
2023 mExecutor = exe;
2024 }
2025 }
2026
2027 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002028 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002029
jiabinf40141d2020-08-07 17:27:48 -07002030 private final class StrategyPreferredDevicesDispatcherStub
2031 extends IStrategyPreferredDevicesDispatcher.Stub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002032
2033 @Override
jiabinf40141d2020-08-07 17:27:48 -07002034 public void dispatchPrefDevicesChanged(int strategyId,
2035 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002036 // make a shallow copy of listeners so callback is not executed under lock
2037 final ArrayList<PrefDevListenerInfo> prefDevListeners;
2038 synchronized (mPrefDevListenerLock) {
2039 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) {
2040 return;
2041 }
2042 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone();
2043 }
2044 final AudioProductStrategy strategy =
2045 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2046 final long ident = Binder.clearCallingIdentity();
2047 try {
2048 for (PrefDevListenerInfo info : prefDevListeners) {
2049 info.mExecutor.execute(() ->
jiabinf40141d2020-08-07 17:27:48 -07002050 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices));
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002051 }
2052 } finally {
2053 Binder.restoreCallingIdentity(ident);
2054 }
2055 }
2056 }
2057
2058 @GuardedBy("mPrefDevListenerLock")
2059 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo(
jiabinf40141d2020-08-07 17:27:48 -07002060 OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002061 if (mPrefDevListeners == null) {
2062 return null;
2063 }
2064 for (PrefDevListenerInfo info : mPrefDevListeners) {
2065 if (info.mListener == listener) {
2066 return info;
2067 }
2068 }
2069 return null;
2070 }
2071
2072 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002073 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002074 return getPrefDevListenerInfo(listener) != null;
2075 }
2076
2077 @GuardedBy("mPrefDevListenerLock")
2078 /**
2079 * @return true if the listener was removed from the list
2080 */
jiabinf40141d2020-08-07 17:27:48 -07002081 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002082 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener);
2083 if (infoToRemove != null) {
2084 mPrefDevListeners.remove(infoToRemove);
2085 return true;
2086 }
2087 return false;
2088 }
2089
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002090 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002091 // Audio Capture Preset routing
2092
2093 /**
2094 * @hide
2095 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2096 * this capture preset. Note that the device may not be available at the time the preferred
2097 * device is set, but it will be used once made available.
2098 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2099 * for this capture preset.</p>
2100 * @param capturePreset the audio capture preset whose routing will be affected
2101 * @param device the audio device to route to when available
2102 * @return true if the operation was successful, false otherwise
2103 */
2104 @SystemApi
2105 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002106 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002107 @NonNull AudioDeviceAttributes device) {
2108 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2109 }
2110
2111 /**
2112 * @hide
2113 * Remove all the preferred audio devices previously set
2114 * @param capturePreset the audio capture preset whose routing will be affected
2115 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2116 * device set for example)
2117 */
2118 @SystemApi
2119 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002120 public boolean clearPreferredDevicesForCapturePreset(
2121 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002122 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2123 return false;
2124 }
2125 try {
2126 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2127 return status == AudioSystem.SUCCESS;
2128 } catch (RemoteException e) {
2129 throw e.rethrowFromSystemServer();
2130 }
2131 }
2132
2133 /**
2134 * @hide
2135 * Return the preferred devices for an audio capture preset, previously set with
2136 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2137 * @param capturePreset the capture preset to query
2138 * @return a list that contains preferred devices for that capture preset.
2139 */
2140 @NonNull
2141 @SystemApi
2142 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002143 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2144 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002145 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2146 return new ArrayList<AudioDeviceAttributes>();
2147 }
2148 try {
2149 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2150 } catch (RemoteException e) {
2151 throw e.rethrowFromSystemServer();
2152 }
2153 }
2154
2155 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002156 @MediaRecorder.SystemSource int capturePreset,
2157 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002158 Objects.requireNonNull(devices);
2159 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2160 return false;
2161 }
2162 if (devices.size() != 1) {
2163 throw new IllegalArgumentException(
2164 "Only support setting one preferred devices for capture preset");
2165 }
2166 for (AudioDeviceAttributes device : devices) {
2167 Objects.requireNonNull(device);
2168 }
2169 try {
2170 final int status =
2171 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2172 return status == AudioSystem.SUCCESS;
2173 } catch (RemoteException e) {
2174 throw e.rethrowFromSystemServer();
2175 }
2176 }
2177
2178 /**
2179 * @hide
2180 * Interface to be notified of changes in the preferred audio devices set for a given capture
2181 * preset.
2182 * <p>Note that this listener will only be invoked whenever
2183 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2184 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2185 * preferred device. It will not be invoked directly after registration with
2186 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2187 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2188 * to indicate which strategies had preferred devices at the time of registration.</p>
2189 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2190 * @see #clearPreferredDevicesForCapturePreset(int)
2191 * @see #getPreferredDevicesForCapturePreset(int)
2192 */
2193 @SystemApi
2194 public interface OnPreferredDevicesForCapturePresetChangedListener {
2195 /**
2196 * Called on the listener to indicate that the preferred audio devices for the given
2197 * capture preset has changed.
2198 * @param capturePreset the capture preset whose preferred device changed
2199 * @param devices a list of newly set preferred audio devices
2200 */
2201 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002202 @MediaRecorder.SystemSource int capturePreset,
2203 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002204 }
2205
2206 /**
2207 * @hide
2208 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2209 * @param executor
2210 * @param listener
2211 * @throws SecurityException if the caller doesn't hold the required permission
2212 */
2213 @SystemApi
2214 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2215 public void addOnPreferredDevicesForCapturePresetChangedListener(
2216 @NonNull @CallbackExecutor Executor executor,
2217 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2218 throws SecurityException {
2219 Objects.requireNonNull(executor);
2220 Objects.requireNonNull(listener);
2221 int status = addOnDevRoleForCapturePresetChangedListener(
2222 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2223 if (status == AudioSystem.ERROR) {
2224 // This must not happen
2225 throw new RuntimeException("Unknown error happened");
2226 }
2227 if (status == AudioSystem.BAD_VALUE) {
2228 throw new IllegalArgumentException(
2229 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2230 + "on a previously registered listener");
2231 }
2232 }
2233
2234 /**
2235 * @hide
2236 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2237 * @param listener
2238 */
2239 @SystemApi
2240 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2241 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2242 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2243 Objects.requireNonNull(listener);
2244 int status = removeOnDevRoleForCapturePresetChangedListener(
2245 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2246 if (status == AudioSystem.ERROR) {
2247 // This must not happen
2248 throw new RuntimeException("Unknown error happened");
2249 }
2250 if (status == AudioSystem.BAD_VALUE) {
2251 throw new IllegalArgumentException(
2252 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2253 + "on an unregistered listener");
2254 }
2255 }
2256
2257 private <T> int addOnDevRoleForCapturePresetChangedListener(
2258 @NonNull @CallbackExecutor Executor executor,
2259 @NonNull T listener, int deviceRole) {
2260 Objects.requireNonNull(executor);
2261 Objects.requireNonNull(listener);
2262 DevRoleListeners<T> devRoleListeners =
2263 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2264 if (devRoleListeners == null) {
2265 return AudioSystem.ERROR;
2266 }
2267 synchronized (devRoleListeners.mDevRoleListenersLock) {
2268 if (devRoleListeners.hasDevRoleListener(listener)) {
2269 return AudioSystem.BAD_VALUE;
2270 }
2271 // lazy initialization of the list of device role listener
2272 if (devRoleListeners.mListenerInfos == null) {
2273 devRoleListeners.mListenerInfos = new ArrayList<>();
2274 }
2275 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2276 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2277 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2278 // register binder for callbacks
2279 synchronized (mDevRoleForCapturePresetListenersLock) {
2280 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2281 mDeviceRoleListenersStatus |= (1 << deviceRole);
2282 if (deviceRoleListenerStatus != 0) {
2283 // There are already device role changed listeners active.
2284 return AudioSystem.SUCCESS;
2285 }
2286 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2287 mDevicesRoleForCapturePresetDispatcherStub =
2288 new CapturePresetDevicesRoleDispatcherStub();
2289 }
2290 try {
2291 getService().registerCapturePresetDevicesRoleDispatcher(
2292 mDevicesRoleForCapturePresetDispatcherStub);
2293 } catch (RemoteException e) {
2294 throw e.rethrowFromSystemServer();
2295 }
2296 }
2297 }
2298 }
2299 return AudioSystem.SUCCESS;
2300 }
2301
2302 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2303 @NonNull T listener, int deviceRole) {
2304 Objects.requireNonNull(listener);
2305 DevRoleListeners<T> devRoleListeners =
2306 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2307 if (devRoleListeners == null) {
2308 return AudioSystem.ERROR;
2309 }
2310 synchronized (devRoleListeners.mDevRoleListenersLock) {
2311 if (!devRoleListeners.removeDevRoleListener(listener)) {
2312 return AudioSystem.BAD_VALUE;
2313 }
2314 if (devRoleListeners.mListenerInfos.size() == 0) {
2315 // unregister binder for callbacks
2316 synchronized (mDevRoleForCapturePresetListenersLock) {
2317 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2318 if (mDeviceRoleListenersStatus != 0) {
2319 // There are some other device role changed listeners active.
2320 return AudioSystem.SUCCESS;
2321 }
2322 try {
2323 getService().unregisterCapturePresetDevicesRoleDispatcher(
2324 mDevicesRoleForCapturePresetDispatcherStub);
2325 } catch (RemoteException e) {
2326 throw e.rethrowFromSystemServer();
2327 }
2328 }
2329 }
2330 }
2331 return AudioSystem.SUCCESS;
2332 }
2333
2334 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
2335 put(AudioSystem.DEVICE_ROLE_PREFERRED,
2336 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
2337 }};
2338
2339 private class DevRoleListenerInfo<T> {
2340 final @NonNull Executor mExecutor;
2341 final @NonNull T mListener;
2342 DevRoleListenerInfo(Executor executor, T listener) {
2343 mExecutor = executor;
2344 mListener = listener;
2345 }
2346 }
2347
2348 private class DevRoleListeners<T> {
2349 private final Object mDevRoleListenersLock = new Object();
2350 @GuardedBy("mDevRoleListenersLock")
2351 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2352
2353 @GuardedBy("mDevRoleListenersLock")
2354 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2355 if (mListenerInfos == null) {
2356 return null;
2357 }
2358 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2359 if (listenerInfo.mListener == listener) {
2360 return listenerInfo;
2361 }
2362 }
2363 return null;
2364 }
2365
2366 @GuardedBy("mDevRoleListenersLock")
2367 private boolean hasDevRoleListener(T listener) {
2368 return getDevRoleListenerInfo(listener) != null;
2369 }
2370
2371 @GuardedBy("mDevRoleListenersLock")
2372 private boolean removeDevRoleListener(T listener) {
2373 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2374 if (infoToRemove != null) {
2375 mListenerInfos.remove(infoToRemove);
2376 return true;
2377 }
2378 return false;
2379 }
2380 }
2381
2382 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2383 /**
2384 * Record if there is a listener added for device role change. If there is a listener added for
2385 * a specified device role change, the bit at position `1 << device_role` is set.
2386 */
2387 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2388 private int mDeviceRoleListenersStatus = 0;
2389 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2390 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2391
2392 private final class CapturePresetDevicesRoleDispatcherStub
2393 extends ICapturePresetDevicesRoleDispatcher.Stub {
2394
2395 @Override
2396 public void dispatchDevicesRoleChanged(
2397 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2398 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2399 if (listenersObj == null) {
2400 return;
2401 }
2402 switch (role) {
2403 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2404 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2405 listeners =
2406 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2407 listenersObj;
2408 final ArrayList<DevRoleListenerInfo<
2409 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2410 synchronized (listeners.mDevRoleListenersLock) {
2411 if (listeners.mListenerInfos.isEmpty()) {
2412 return;
2413 }
2414 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2415 OnPreferredDevicesForCapturePresetChangedListener>>)
2416 listeners.mListenerInfos.clone();
2417 }
2418 final long ident = Binder.clearCallingIdentity();
2419 try {
2420 for (DevRoleListenerInfo<
2421 OnPreferredDevicesForCapturePresetChangedListener> info :
2422 prefDevListeners) {
2423 info.mExecutor.execute(() ->
2424 info.mListener.onPreferredDevicesForCapturePresetChanged(
2425 capturePreset, devices));
2426 }
2427 } finally {
2428 Binder.restoreCallingIdentity(ident);
2429 }
2430 } break;
2431 default:
2432 break;
2433 }
2434 }
2435 }
2436
2437 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002438 // Direct playback query
2439
2440 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2441 direct playback not supported. */
2442 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2443 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2444 direct offload playback supported. Compressed offload is a variant of direct playback.
2445 It is the feature that allows audio processing tasks to be done on the Android device but
2446 not on the application processor, instead, it is handled by dedicated hardware such as audio
2447 DSPs. That will allow the application processor to be idle as much as possible, which is
2448 good for power saving. Compressed offload playback supports
2449 {@link AudioTrack.StreamEventCallback} for event notifications. */
2450 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2451 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2452 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2453 direct offload playback supported with gapless transitions. Compressed offload is a variant
2454 of direct playback. It is the feature that allows audio processing tasks to be done on the
2455 Android device but not on the application processor, instead, it is handled by dedicated
2456 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2457 possible, which is good for power saving. Compressed offload playback supports
2458 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2459 indicates the ability to play consecutive audio tracks without an audio silence in
2460 between. */
2461 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2462 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2463 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2464 direct playback supported. This value covers direct playback that is bitstream pass-through
2465 such as compressed pass-through. */
2466 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2467 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2468
2469 /** @hide */
2470 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2471 DIRECT_PLAYBACK_NOT_SUPPORTED,
2472 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2473 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2474 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2475 )
2476 @Retention(RetentionPolicy.SOURCE)
2477 public @interface AudioDirectPlaybackMode {}
2478
2479 /**
2480 * Returns a bitfield representing the different forms of direct playback currently available
2481 * for a given audio format.
2482 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2483 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2484 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2485 * passthrough.
2486 * <p>Checking for direct support can help the app select the representation of audio content
2487 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2488 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2489 * streams, if needed.
2490 * @param format the audio format (codec, sample rate, channels) being checked.
2491 * @param attributes the {@link AudioAttributes} to be used for playback
2492 * @return the direct playback mode available with given format and attributes. The returned
2493 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2494 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2495 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2496 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2497 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2498 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2499 */
2500 @AudioDirectPlaybackMode
2501 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2502 @NonNull AudioAttributes attributes) {
2503 Objects.requireNonNull(format);
2504 Objects.requireNonNull(attributes);
2505 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2506 }
2507
2508 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002509 // Offload query
2510 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002511 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002512 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2513 * is not competing with other software resources. In general, it is supported by dedicated
2514 * hardware, such as audio DSPs.
2515 * <p>Note that this query only provides information about the support of an audio format,
2516 * it does not indicate whether the resources necessary for the offloaded playback are
2517 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002518 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002519 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002520 * @return true if the given audio format can be offloaded.
2521 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002522 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2523 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002524 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002525 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002526 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002527 if (attributes == null) {
2528 throw new NullPointerException("Illegal null AudioAttributes");
2529 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002530 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2531 }
2532
2533 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2534 offload playback not supported */
2535 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2536 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2537 offload playback supported */
2538 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2539 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2540 offload playback supported with gapless transitions */
2541 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2542 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2543
2544 /** @hide */
2545 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2546 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2547 PLAYBACK_OFFLOAD_SUPPORTED,
2548 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2549 )
2550 @Retention(RetentionPolicy.SOURCE)
2551 public @interface AudioOffloadMode {}
2552
2553 /**
2554 * Returns whether offloaded playback of an audio format is supported on the device or not and
2555 * when supported whether gapless transitions are possible or not.
2556 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2557 * is not competing with other software resources. In general, it is supported by dedicated
2558 * hardware, such as audio DSPs.
2559 * <p>Note that this query only provides information about the support of an audio format,
2560 * it does not indicate whether the resources necessary for the offloaded playback are
2561 * available at that instant.
2562 * @param format the audio format (codec, sample rate, channels) being checked.
2563 * @param attributes the {@link AudioAttributes} to be used for playback
2564 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2565 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2566 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2567 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002568 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002569 */
jiabine22f6aa2021-12-10 01:09:02 +00002570 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002571 @AudioOffloadMode
2572 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2573 @NonNull AudioAttributes attributes) {
2574 if (format == null) {
2575 throw new NullPointerException("Illegal null AudioFormat");
2576 }
2577 if (attributes == null) {
2578 throw new NullPointerException("Illegal null AudioAttributes");
2579 }
2580 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002581 }
2582
2583 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002584 // Immersive audio
2585
2586 /**
2587 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002588 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002589 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2590 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002591 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002592 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002593 return new Spatializer(this);
2594 }
2595
2596 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002597 // Bluetooth SCO control
2598 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002599 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002600 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002601 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2602 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2603 *
2604 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002605 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002606 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002607 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002608 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2609 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2610 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002611
2612 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002613 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002614 * connection state has been updated.
2615 * <p>This intent has two extras:
2616 * <ul>
2617 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2618 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2619 * </ul>
2620 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2621 * <ul>
2622 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2623 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2624 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2625 * </ul>
2626 * @see #startBluetoothSco()
2627 */
2628 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2629 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2630 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2631
Eric Laurent3def1ee2010-03-17 23:26:26 -07002632 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002633 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2634 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002635 */
2636 public static final String EXTRA_SCO_AUDIO_STATE =
2637 "android.media.extra.SCO_AUDIO_STATE";
2638
2639 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002640 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2641 * bluetooth SCO connection state.
2642 */
2643 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2644 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2645
2646 /**
2647 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2648 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002649 */
2650 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2651 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002652 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2653 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002654 */
2655 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2656 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002657 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2658 * indicating that the SCO audio channel is being established
2659 */
2660 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2661 /**
2662 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002663 * there was an error trying to obtain the state
2664 */
2665 public static final int SCO_AUDIO_STATE_ERROR = -1;
2666
2667
2668 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002669 * Indicates if current platform supports use of SCO for off call use cases.
2670 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002671 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002672 * feature.
2673 * @return true if bluetooth SCO can be used for audio when not in call
2674 * false otherwise
2675 * @see #startBluetoothSco()
2676 */
2677 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002678 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002679 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2680 }
2681
2682 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002683 * Start bluetooth SCO audio connection.
2684 * <p>Requires Permission:
2685 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2686 * <p>This method can be used by applications wanting to send and received audio
2687 * to/from a bluetooth SCO headset while the phone is not in call.
2688 * <p>As the SCO connection establishment can take several seconds,
2689 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002690 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002691 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002692 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2693 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2694 * registration. If the state is already CONNECTED, no state change will be received via the
2695 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2696 * so that the connection stays active in case the current initiator stops the connection.
2697 * <p>Unless the connection is already active as described above, the state will always
2698 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2699 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2700 * <p>When finished with the SCO connection or if the establishment fails, the application must
2701 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002702 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2703 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002704 * <ul>
2705 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2706 * <li> the format must be mono </li>
2707 * <li> the sampling must be 16kHz or 8kHz </li>
2708 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002709 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002710 * <ul>
2711 * <li> the format must be mono </li>
2712 * <li> the sampling must be 8kHz </li>
2713 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002714 * <p>Note that the phone application always has the priority on the usage of the SCO
2715 * connection for telephony. If this method is called while the phone is in call
2716 * it will be ignored. Similarly, if a call is received or sent while an application
2717 * is using the SCO connection, the connection will be lost for the application and NOT
2718 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002719 * <p>NOTE: up to and including API version
2720 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2721 * voice call to the bluetooth headset.
2722 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2723 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002724 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002725 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurent3def1ee2010-03-17 23:26:26 -07002726 */
2727 public void startBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002728 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002729 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002730 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002731 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002732 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002733 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002734 }
2735 }
2736
2737 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002738 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002739 * Start bluetooth SCO audio connection in virtual call mode.
2740 * <p>Requires Permission:
2741 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2742 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2743 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2744 * virtual call mode.
2745 * Applications using voice input for search or commands should first try raw audio connection
2746 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2747 * failure.
2748 * @see #startBluetoothSco()
2749 * @see #stopBluetoothSco()
2750 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2751 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002752 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002753 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002754 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002755 try {
2756 service.startBluetoothScoVirtualCall(mICallBack);
2757 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002758 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002759 }
2760 }
2761
2762 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002763 * Stop bluetooth SCO audio connection.
2764 * <p>Requires Permission:
2765 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2766 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002767 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2768 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002769 * @see #startBluetoothSco()
2770 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002771 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002772 public void stopBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002773 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002774 try {
2775 service.stopBluetoothSco(mICallBack);
2776 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002777 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002778 }
2779 }
2780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002782 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002783 * <p>
2784 * This method should only be used by applications that replace the platform-wide
2785 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 *
Eric Laurenta553c252009-07-17 12:17:14 -07002787 * @param on set <var>true</var> to use bluetooth SCO for communications;
2788 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 */
2790 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002791 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002792 try {
2793 service.setBluetoothScoOn(on);
2794 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002795 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002797 }
2798
2799 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002800 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002801 *
Eric Laurenta553c252009-07-17 12:17:14 -07002802 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002803 * false if otherwise
2804 */
2805 public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002806 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002807 try {
2808 return service.isBluetoothScoOn();
2809 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002810 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002812 }
2813
2814 /**
Eric Laurent242b3382012-06-15 11:48:50 -07002815 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2816 * headset; <var>false</var> disable A2DP audio
Eric Laurenta553c252009-07-17 12:17:14 -07002817 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002818 */
Eric Laurenta553c252009-07-17 12:17:14 -07002819 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820 }
2821
2822 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002823 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002825 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002826 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002827 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002828 */
2829 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002830 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002831 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2832 return true;
2833 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2834 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2835 return true;
2836 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2837 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002838 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002839 }
Eric Laurent9656df22016-04-20 16:42:28 -07002840 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002841 }
2842
2843 /**
2844 * Sets audio routing to the wired headset on or off.
2845 *
2846 * @param on set <var>true</var> to route audio to/from wired
2847 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002848 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002849 */
Eric Laurenta553c252009-07-17 12:17:14 -07002850 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 }
2852
2853 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002854 * Checks whether a wired headset is connected or not.
2855 * <p>This is not a valid indication that audio playback is
2856 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002858 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002859 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002860 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002861 */
2862 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002863 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002864 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002865 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002866 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2867 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2868 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002869 return false;
2870 } else {
2871 return true;
2872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002873 }
2874
2875 /**
2876 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002877 * <p>
2878 * This method should only be used by applications that replace the platform-wide
2879 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880 *
2881 * @param on set <var>true</var> to mute the microphone;
2882 * <var>false</var> to turn mute off
2883 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002884 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002885 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002886 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002887 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002888 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002889 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002890 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002892 }
2893
2894 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002895 * @hide
2896 * Sets the microphone from switch mute on or off.
2897 * <p>
2898 * This method should only be used by InputManager to notify
2899 * Audio Subsystem about Microphone Mute switch state.
2900 *
2901 * @param on set <var>true</var> to mute the microphone;
2902 * <var>false</var> to turn mute off
2903 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002904 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002905 public void setMicrophoneMuteFromSwitch(boolean on) {
2906 final IAudioService service = getService();
2907 try {
2908 service.setMicrophoneMuteFromSwitch(on);
2909 } catch (RemoteException e) {
2910 throw e.rethrowFromSystemServer();
2911 }
2912 }
2913
2914 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 * Checks whether the microphone mute is on or off.
2916 *
2917 * @return true if microphone is muted, false if it's not
2918 */
2919 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002920 final IAudioService service = getService();
2921 try {
2922 return service.isMicrophoneMuted();
2923 } catch (RemoteException e) {
2924 throw e.rethrowFromSystemServer();
2925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 }
2927
2928 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002929 * Broadcast Action: microphone muting state changed.
2930 *
2931 * You <em>cannot</em> receive this through components declared
2932 * in manifests, only by explicitly registering for it with
2933 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2934 * Context.registerReceiver()}.
2935 *
2936 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2937 * microphone is muted.
2938 */
2939 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2940 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2941 "android.media.action.MICROPHONE_MUTE_CHANGED";
2942
2943 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07002944 * Broadcast Action: speakerphone state changed.
2945 *
2946 * You <em>cannot</em> receive this through components declared
2947 * in manifests, only by explicitly registering for it with
2948 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2949 * Context.registerReceiver()}.
2950 *
2951 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2952 * speakerphone functionality is enabled or not.
2953 */
2954 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2955 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2956 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2957
2958 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002960 * <p>
2961 * The audio mode encompasses audio routing AND the behavior of
2962 * the telephony layer. Therefore this method should only be used by applications that
2963 * replace the platform-wide management of audio settings or the main telephony application.
2964 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2965 * application when it places a phone call, as it will cause signals from the radio layer
2966 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002968 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 * Informs the HAL about the current audio state so that
2970 * it can route the audio appropriately.
2971 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002972 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002973 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07002975 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002977 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002978 }
2979 }
2980
2981 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01002982 * This change id controls use of audio modes for call audio redirection.
2983 * @hide
2984 */
2985 @ChangeId
2986 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
2987 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
2988
2989 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002990 * Returns the current audio mode.
2991 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002992 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002994 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002996 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002998 int mode = service.getMode();
2999 int sdk;
3000 try {
3001 sdk = getContext().getApplicationInfo().targetSdkVersion;
3002 } catch (NullPointerException e) {
3003 // some tests don't have a Context
3004 sdk = Build.VERSION.SDK_INT;
3005 }
3006 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3007 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01003008 } else if (mode == MODE_CALL_REDIRECT
3009 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3010 mode = MODE_IN_CALL;
3011 } else if (mode == MODE_COMMUNICATION_REDIRECT
3012 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3013 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003014 }
3015 return mode;
3016 } catch (RemoteException e) {
3017 throw e.rethrowFromSystemServer();
3018 }
3019 }
3020
3021 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003022 * Interface definition of a callback that is notified when the audio mode changes
3023 */
3024 public interface OnModeChangedListener {
3025 /**
3026 * Called on the listener to indicate that the audio mode has changed
3027 *
3028 * @param mode The current audio mode
3029 */
3030 void onModeChanged(@AudioMode int mode);
3031 }
3032
Nate Myren08635fe2021-04-20 12:04:39 -07003033 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003034 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003035 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003036 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3037 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003038
Nate Myren08635fe2021-04-20 12:04:39 -07003039
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003040 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3041 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003042
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003043 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003044 public void register(boolean register) {
3045 try {
3046 if (register) {
3047 getService().registerModeDispatcher(this);
3048 } else {
3049 getService().unregisterModeDispatcher(this);
3050 }
3051 } catch (RemoteException e) {
3052 e.rethrowFromSystemServer();
3053 }
3054 }
Nate Myren08635fe2021-04-20 12:04:39 -07003055
3056 @Override
3057 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003058 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003059 }
3060 }
3061
Nate Myren08635fe2021-04-20 12:04:39 -07003062 /**
3063 * Adds a listener to be notified of changes to the audio mode.
3064 * See {@link #getMode()}
3065 * @param executor
3066 * @param listener
3067 */
3068 public void addOnModeChangedListener(
3069 @NonNull @CallbackExecutor Executor executor,
3070 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003071 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3072 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003073 }
3074
3075 /**
3076 * Removes a previously added listener for changes to audio mode.
3077 * See {@link #getMode()}
3078 * @param listener
3079 */
3080 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003081 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003082 }
3083
3084 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003085 * Indicates if the platform supports a special call screening and call monitoring mode.
3086 * <p>
3087 * When this mode is supported, it is possible to perform call screening and monitoring
3088 * functions while other use cases like music or movie playback are active.
3089 * <p>
3090 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3091 * call screening mode.
3092 * <p>
3093 * If call screening mode is not supported, setting mode to
3094 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3095 * {@link #getMode()}.
3096 * @return true if call screening mode is supported, false otherwise.
3097 */
3098 public boolean isCallScreeningModeSupported() {
3099 final IAudioService service = getService();
3100 try {
3101 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003103 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 }
3105 }
3106
3107 /* modes for setMode/getMode/setRoute/getRoute */
3108 /**
3109 * Audio harware modes.
3110 */
3111 /**
3112 * Invalid audio mode.
3113 */
3114 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3115 /**
3116 * Current audio mode. Used to apply audio routing to current mode.
3117 */
3118 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3119 /**
3120 * Normal audio mode: not ringing and no call established.
3121 */
3122 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3123 /**
3124 * Ringing audio mode. An incoming is being signaled.
3125 */
3126 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3127 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003128 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 */
3130 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003131 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003132 * In communication audio mode. An audio/video chat or VoIP call is established.
3133 */
3134 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003135 /**
3136 * Call screening in progress. Call is connected and audio is accessible to call
3137 * screening applications but other audio use cases are still possible.
3138 */
3139 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3140
Eric Laurent1c3408f2021-11-09 12:09:54 +01003141 /**
3142 * A telephony call is established and its audio is being redirected to another device.
3143 */
3144 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3145
3146 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003147 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003148 * device.
3149 */
3150 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3151
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003152 /** @hide */
3153 @IntDef(flag = false, prefix = "MODE_", value = {
3154 MODE_NORMAL,
3155 MODE_RINGTONE,
3156 MODE_IN_CALL,
3157 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003158 MODE_CALL_SCREENING,
3159 MODE_CALL_REDIRECT,
3160 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003161 )
3162 @Retention(RetentionPolicy.SOURCE)
3163 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164
3165 /* Routing bits for setRouting/getRouting API */
3166 /**
3167 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003168 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3169 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 */
Eric Laurenta553c252009-07-17 12:17:14 -07003171 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003173 * Routing audio output to speaker
3174 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3175 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 */
Eric Laurenta553c252009-07-17 12:17:14 -07003177 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003178 /**
3179 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003180 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3181 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 */
3183 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3184 /**
3185 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003186 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3187 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 */
Eric Laurenta553c252009-07-17 12:17:14 -07003189 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 /**
3191 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003192 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3193 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 */
Eric Laurenta553c252009-07-17 12:17:14 -07003195 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 /**
3197 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003198 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3199 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 */
Eric Laurenta553c252009-07-17 12:17:14 -07003201 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 /**
3203 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003204 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3205 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 */
Eric Laurenta553c252009-07-17 12:17:14 -07003207 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208
3209 /**
3210 * Sets the audio routing for a specified mode
3211 *
3212 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3213 * @param routes bit vector of routes requested, created from one or
3214 * more of ROUTE_xxx types. Set bits indicate that route should be on
3215 * @param mask bit vector of routes to change, created from one or more of
3216 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003217 *
3218 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003219 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 */
Eric Laurenta553c252009-07-17 12:17:14 -07003221 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 }
3224
3225 /**
3226 * Returns the current audio routing bit vector for a specified mode.
3227 *
3228 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3229 * @return an audio route bit vector that can be compared with ROUTE_xxx
3230 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003231 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3232 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003234 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003235 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003236 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 }
3238
3239 /**
3240 * Checks whether any music is active.
3241 *
3242 * @return true if any music tracks are active.
3243 */
3244 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003245 final IAudioService service = getService();
3246 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003247 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003248 } catch (RemoteException e) {
3249 throw e.rethrowFromSystemServer();
3250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 }
3252
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003253 /**
3254 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003255 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3256 * display). Note that BT audio sinks are not considered remote devices.
3257 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3258 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003259 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003260 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003261 final IAudioService service = getService();
3262 try {
3263 return service.isMusicActive(true /*remotely*/);
3264 } catch (RemoteException e) {
3265 throw e.rethrowFromSystemServer();
3266 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003267 }
3268
3269 /**
3270 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003271 * Checks whether the current audio focus is exclusive.
3272 * @return true if the top of the audio focus stack requested focus
3273 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3274 */
3275 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003276 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003277 try {
3278 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3279 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003280 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003281 }
3282 }
3283
3284 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003285 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003286 * An audio session identifier is a system wide unique identifier for a set of audio streams
3287 * (one or more mixed together).
3288 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3289 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3290 * session ID will be applied to the mixed audio content of the players that share the same
3291 * audio session.
3292 * <p>This method can for instance be used when creating one of the
3293 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3294 * or to specify a session for a speech synthesis utterance
3295 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003296 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003297 * system failed to generate a new session, a condition in which audio playback or recording
3298 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003299 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003300 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003301 int session = AudioSystem.newAudioSessionId();
3302 if (session > 0) {
3303 return session;
3304 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003305 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003306 return ERROR;
3307 }
3308 }
3309
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003310 /**
3311 * A special audio session ID to indicate that the audio session ID isn't known and the
3312 * framework should generate a new value. This can be used when building a new
3313 * {@link AudioTrack} instance with
3314 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3315 */
3316 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3317
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 /*
3320 * Sets a generic audio configuration parameter. The use of these parameters
3321 * are platform dependant, see libaudio
3322 *
3323 * ** Temporary interface - DO NOT USE
3324 *
3325 * TODO: Replace with a more generic key:value get/set mechanism
3326 *
3327 * param key name of parameter to set. Must not be null.
3328 * param value value of parameter. Must not be null.
3329 */
3330 /**
3331 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003332 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 */
Eric Laurenta553c252009-07-17 12:17:14 -07003334 @Deprecated public void setParameter(String key, String value) {
3335 setParameters(key+"="+value);
3336 }
3337
3338 /**
3339 * Sets a variable number of parameter values to audio hardware.
3340 *
3341 * @param keyValuePairs list of parameters key value pairs in the form:
3342 * key1=value1;key2=value2;...
3343 *
3344 */
3345 public void setParameters(String keyValuePairs) {
3346 AudioSystem.setParameters(keyValuePairs);
3347 }
3348
3349 /**
William Escandeef429b62021-10-15 18:37:40 +02003350 * @hide
3351 */
3352 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3353 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3354 public void setHfpEnabled(boolean enable) {
3355 AudioSystem.setParameters("hfp_enable=" + enable);
3356 }
3357
3358 /**
3359 * @hide
3360 */
3361 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3362 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3363 public void setHfpVolume(int volume) {
3364 AudioSystem.setParameters("hfp_volume=" + volume);
3365 }
3366
3367 /**
3368 * @hide
3369 */
3370 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3371 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3372 public void setHfpSamplingRate(int rate) {
3373 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3374 }
3375
3376 /**
3377 * @hide
3378 */
3379 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3380 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3381 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3382 boolean hasWbsEnabled) {
3383 AudioSystem.setParameters("bt_headset_name=" + name
3384 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3385 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3386 }
3387
3388 /**
3389 * @hide
3390 */
3391 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3392 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3393 public void setA2dpSuspended(boolean enable) {
3394 AudioSystem.setParameters("A2dpSuspended=" + enable);
3395 }
3396
3397 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003398 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003399 *
3400 * @param keys list of parameters
3401 * @return list of parameters key value pairs in the form:
3402 * key1=value1;key2=value2;...
3403 */
3404 public String getParameters(String keys) {
3405 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 }
3407
3408 /* Sound effect identifiers */
3409 /**
3410 * Keyboard and direction pad click sound
3411 * @see #playSoundEffect(int)
3412 */
3413 public static final int FX_KEY_CLICK = 0;
3414 /**
3415 * Focus has moved up
3416 * @see #playSoundEffect(int)
3417 */
3418 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3419 /**
3420 * Focus has moved down
3421 * @see #playSoundEffect(int)
3422 */
3423 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3424 /**
3425 * Focus has moved left
3426 * @see #playSoundEffect(int)
3427 */
3428 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3429 /**
3430 * Focus has moved right
3431 * @see #playSoundEffect(int)
3432 */
3433 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3434 /**
3435 * IME standard keypress sound
3436 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 */
3438 public static final int FX_KEYPRESS_STANDARD = 5;
3439 /**
3440 * IME spacebar keypress sound
3441 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442 */
3443 public static final int FX_KEYPRESS_SPACEBAR = 6;
3444 /**
3445 * IME delete keypress sound
3446 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 */
3448 public static final int FX_KEYPRESS_DELETE = 7;
3449 /**
3450 * IME return_keypress sound
3451 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003452 */
3453 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003454
3455 /**
3456 * Invalid keypress sound
3457 * @see #playSoundEffect(int)
3458 */
3459 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003460
3461 /**
3462 * Back sound
3463 * @see #playSoundEffect(int)
3464 */
3465 public static final int FX_BACK = 10;
3466
3467 /**
3468 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003469 * <p>
3470 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3471 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003472 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3473 * @see #playSoundEffect(int)
3474 */
3475 public static final int FX_HOME = 11;
3476
3477 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003478 * @hide Navigation repeat sound 1
3479 * <p>
3480 * To be played by the framework when a focus navigation is repeatedly triggered
3481 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003482 * This is currently only used on TV devices.
3483 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3484 * @see #playSoundEffect(int)
3485 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003486 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003487
3488 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003489 * @hide Navigation repeat sound 2
3490 * <p>
3491 * To be played by the framework when a focus navigation is repeatedly triggered
3492 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003493 * This is currently only used on TV devices.
3494 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3495 * @see #playSoundEffect(int)
3496 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003497 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003498
3499 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003500 * @hide Navigation repeat sound 3
3501 * <p>
3502 * To be played by the framework when a focus navigation is repeatedly triggered
3503 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003504 * This is currently only used on TV devices.
3505 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3506 * @see #playSoundEffect(int)
3507 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003508 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003509
3510 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003511 * @hide Navigation repeat sound 4
3512 * <p>
3513 * To be played by the framework when a focus navigation is repeatedly triggered
3514 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003515 * This is currently only used on TV devices.
3516 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3517 * @see #playSoundEffect(int)
3518 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003519 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 /**
3522 * @hide Number of sound effects
3523 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003524 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003525 public static final int NUM_SOUND_EFFECTS = 16;
3526
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003527 /** @hide */
3528 @IntDef(prefix = { "FX_" }, value = {
3529 FX_KEY_CLICK,
3530 FX_FOCUS_NAVIGATION_UP,
3531 FX_FOCUS_NAVIGATION_DOWN,
3532 FX_FOCUS_NAVIGATION_LEFT,
3533 FX_FOCUS_NAVIGATION_RIGHT,
3534 FX_KEYPRESS_STANDARD,
3535 FX_KEYPRESS_SPACEBAR,
3536 FX_KEYPRESS_DELETE,
3537 FX_KEYPRESS_RETURN,
3538 FX_KEYPRESS_INVALID,
3539 FX_BACK
3540 })
3541 @Retention(RetentionPolicy.SOURCE)
3542 public @interface SystemSoundEffect {}
3543
Philip Junker7f1fdff2020-12-03 16:10:41 +01003544 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003545 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003546 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003547 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003548
3549 /**
3550 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003551 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3552 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003553 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003554 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003555 switch (n) {
3556 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003557 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003558 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003559 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003560 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003561 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003562 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003563 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003564 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003565 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003566 return -1;
3567 }
3568 }
3569
3570 /**
3571 * @hide
3572 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003573 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003574 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003575 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003576 } catch (RemoteException e) {
3577
3578 }
3579 }
3580
3581 /**
3582 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003583 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003584 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003585 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003586 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003587 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003588 } catch (RemoteException e) {
3589 throw e.rethrowFromSystemServer();
3590 }
3591 }
3592
3593 /**
3594 * @hide
3595 * @param enabled
3596 */
3597 public void setHomeSoundEffectEnabled(boolean enabled) {
3598 try {
3599 getService().setHomeSoundEffectEnabled(enabled);
3600 } catch (RemoteException e) {
3601
3602 }
3603 }
3604
3605 /**
3606 * @hide
3607 * @return true if the home sound effect is enabled
3608 */
3609 public boolean isHomeSoundEffectEnabled() {
3610 try {
3611 return getService().isHomeSoundEffectEnabled();
3612 } catch (RemoteException e) {
3613 throw e.rethrowFromSystemServer();
3614 }
3615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003616
3617 /**
3618 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003619 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003620 * NOTE: This version uses the UI settings to determine
3621 * whether sounds are heard or not.
3622 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003623 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003624 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003625 }
3626
3627 /**
3628 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003629 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003630 * @param userId The current user to pull sound settings from
3631 * NOTE: This version uses the UI settings to determine
3632 * whether sounds are heard or not.
3633 * @hide
3634 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003635 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003636 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3637 return;
3638 }
3639
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003640 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003642 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003643 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003644 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003645 }
3646 }
3647
3648 /**
3649 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003650 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003651 * @param volume Sound effect volume.
3652 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3653 * 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 -08003654 * NOTE: This version is for applications that have their own
3655 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003657 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003658 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3659 return;
3660 }
3661
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003662 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 try {
3664 service.playSoundEffectVolume(effectType, volume);
3665 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003666 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 }
3668 }
3669
3670 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003671 * Load Sound effects.
3672 * This method must be called when sound effects are enabled.
3673 */
3674 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003675 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 try {
3677 service.loadSoundEffects();
3678 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003679 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 }
3681 }
3682
3683 /**
3684 * Unload Sound effects.
3685 * This method can be called to free some memory when
3686 * sound effects are disabled.
3687 */
3688 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003689 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003690 try {
3691 service.unloadSoundEffects();
3692 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003693 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694 }
3695 }
3696
Eric Laurent4050c932009-07-08 02:52:14 -07003697 /**
Andy Hung69836952020-03-26 01:00:15 -07003698 * @hide
3699 */
3700 public static String audioFocusToString(int focus) {
3701 switch (focus) {
3702 case AUDIOFOCUS_NONE:
3703 return "AUDIOFOCUS_NONE";
3704 case AUDIOFOCUS_GAIN:
3705 return "AUDIOFOCUS_GAIN";
3706 case AUDIOFOCUS_GAIN_TRANSIENT:
3707 return "AUDIOFOCUS_GAIN_TRANSIENT";
3708 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3709 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3710 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3711 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3712 case AUDIOFOCUS_LOSS:
3713 return "AUDIOFOCUS_LOSS";
3714 case AUDIOFOCUS_LOSS_TRANSIENT:
3715 return "AUDIOFOCUS_LOSS_TRANSIENT";
3716 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3717 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3718 default:
3719 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3720 }
3721 }
3722
3723 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003724 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003725 */
3726 public static final int AUDIOFOCUS_NONE = 0;
3727
3728 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003729 * 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 -07003730 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003731 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003732 */
3733 public static final int AUDIOFOCUS_GAIN = 1;
3734 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003735 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3736 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3737 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003738 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003739 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003740 */
3741 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003742 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003743 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003744 * amount of time, and where it is acceptable for other audio applications to keep playing
3745 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003746 * Examples of temporary changes are the playback of driving directions where playback of music
3747 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003748 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003749 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3750 */
3751 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3752 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003753 * Used to indicate a temporary request of audio focus, anticipated to last a short
3754 * amount of time, during which no other applications, or system components, should play
3755 * anything. Examples of exclusive and transient audio focus requests are voice
3756 * memo recording and speech recognition, during which the system shouldn't play any
3757 * notifications, and media playback should have paused.
3758 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3759 */
3760 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3761 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003762 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003763 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003764 */
3765 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3766 /**
3767 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003768 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003769 */
3770 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3771 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003772 * 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 -07003773 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3774 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003775 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003776 */
3777 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3778 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003779
3780 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003781 * Interface definition for a callback to be invoked when the audio focus of the system is
3782 * updated.
3783 */
3784 public interface OnAudioFocusChangeListener {
3785 /**
3786 * Called on the listener to notify it the audio focus for this listener has been changed.
3787 * The focusChange value indicates whether the focus was gained,
3788 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3789 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003790 * When losing focus, listeners can use the focus change information to decide what
3791 * behavior to adopt when losing focus. A music player could for instance elect to lower
3792 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3793 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003794 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003795 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003796 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003797 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003798 }
3799
3800 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003801 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3802 */
3803 private static class FocusRequestInfo {
3804 @NonNull final AudioFocusRequest mRequest;
3805 @Nullable final Handler mHandler;
3806 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3807 mRequest = afr;
3808 mHandler = handler;
3809 }
3810 }
3811
3812 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003813 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3814 * to actual listener objects.
3815 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003816 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003817 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3818 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003819
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003820 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003821 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003822 }
3823
3824 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003825 * Handler for events (audio focus change, recording config change) coming from the
3826 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003827 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003828 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003829 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003830
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003831 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003832 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003833 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003834 private final static int MSSG_FOCUS_CHANGE = 0;
3835 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003836 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003837
3838 /**
3839 * Helper class to handle the forwarding of audio service events to the appropriate listener
3840 */
3841 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003842 private final Handler mHandler;
3843
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003844 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003845 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003846 if (handler == null) {
3847 if ((looper = Looper.myLooper()) == null) {
3848 looper = Looper.getMainLooper();
3849 }
3850 } else {
3851 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003852 }
3853
3854 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003855 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003856 mHandler = new Handler(looper) {
3857 @Override
3858 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003859 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003860 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003861 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3862 if (fri != null) {
3863 final OnAudioFocusChangeListener listener =
3864 fri.mRequest.getOnAudioFocusChangeListener();
3865 if (listener != null) {
3866 Log.d(TAG, "dispatching onAudioFocusChange("
3867 + msg.arg1 + ") to " + msg.obj);
3868 listener.onAudioFocusChange(msg.arg1);
3869 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003870 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003871 } break;
3872 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08003873 final RecordConfigChangeCallbackData cbData =
3874 (RecordConfigChangeCallbackData) msg.obj;
3875 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07003876 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08003877 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003878 } break;
3879 case MSSG_PLAYBACK_CONFIG_CHANGE: {
3880 final PlaybackConfigChangeCallbackData cbData =
3881 (PlaybackConfigChangeCallbackData) msg.obj;
3882 if (cbData.mCb != null) {
3883 if (DEBUG) {
3884 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3885 }
3886 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3887 }
3888 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003889 default:
3890 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003891 }
3892 }
3893 };
3894 } else {
3895 mHandler = null;
3896 }
3897 }
3898
3899 Handler getHandler() {
3900 return mHandler;
3901 }
3902 }
3903
Glenn Kasten30c918c2011-11-10 17:56:41 -08003904 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003905 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003906 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003907 final FocusRequestInfo fri = findFocusRequestInfo(id);
3908 if (fri != null) {
3909 final OnAudioFocusChangeListener listener =
3910 fri.mRequest.getOnAudioFocusChangeListener();
3911 if (listener != null) {
3912 final Handler h = (fri.mHandler == null) ?
3913 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3914 final Message m = h.obtainMessage(
3915 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3916 id/*obj*/);
3917 h.sendMessage(m);
3918 }
3919 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003920 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003921
3922 @Override
3923 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3924 synchronized (mFocusRequestsLock) {
3925 // TODO use generation counter as the key instead
3926 final BlockingFocusResultReceiver focusReceiver =
3927 mFocusRequestsAwaitingResult.remove(clientId);
3928 if (focusReceiver != null) {
3929 focusReceiver.notifyResult(requestResult);
3930 } else {
3931 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3932 }
3933 }
3934 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003935 };
3936
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003937 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003938 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07003939 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003940 } else {
3941 return new String(this.toString() + l.toString());
3942 }
3943 }
3944
3945 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003946 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003947 * Registers a listener to be called when audio focus changes and keeps track of the associated
3948 * focus request (including Handler to use for the listener).
3949 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003950 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003951 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3952 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3953 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3954 new ServiceEventHandlerDelegate(h).getHandler());
3955 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3956 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003957 }
3958
3959 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003960 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003961 * Causes the specified listener to not be called anymore when focus is gained or lost.
3962 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003963 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003964 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003965 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003966 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003967 }
3968
3969
3970 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003971 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003972 */
3973 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3974 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003975 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003976 */
3977 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003978 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003979 * A focus change request whose granting is delayed: the request was successful, but the
3980 * requester will only be granted audio focus once the condition that prevented immediate
3981 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003982 * See {@link #requestAudioFocus(AudioFocusRequest)} and
3983 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003984 */
3985 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003986
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003987 /** @hide */
3988 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3989 AUDIOFOCUS_REQUEST_FAILED,
3990 AUDIOFOCUS_REQUEST_GRANTED,
3991 AUDIOFOCUS_REQUEST_DELAYED }
3992 )
3993 @Retention(RetentionPolicy.SOURCE)
3994 public @interface FocusRequestResult {}
3995
3996 /**
3997 * @hide
3998 * code returned when a synchronous focus request on the client-side is to be blocked
3999 * until the external audio focus policy decides on the response for the client
4000 */
4001 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
4002
4003 /**
4004 * Timeout duration in ms when waiting on an external focus policy for the result for a
4005 * focus request
4006 */
4007 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
4008
4009 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4010
4011 private final Object mFocusRequestsLock = new Object();
4012 /**
4013 * Map of all receivers of focus request results, one per unresolved focus request.
4014 * Receivers are added before sending the request to the external focus policy,
4015 * and are removed either after receiving the result, or after the timeout.
4016 * This variable is lazily initialized.
4017 */
4018 @GuardedBy("mFocusRequestsLock")
4019 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4020
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004021
4022 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004023 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004024 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004025 * @param l the listener to be notified of audio focus changes
4026 * @param streamType the main audio stream type affected by the focus request
4027 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4028 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004029 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004030 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4031 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004032 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4033 * that benefits from the system not playing disruptive sounds like notifications, for
4034 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004035 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004036 * as the playback of a song or a video.
4037 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004038 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004039 */
4040 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004041 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4042 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004043 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004044
4045 try {
4046 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4047 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4048 // AUDIOFOCUS_FLAG_DELAY_OK flag
4049 status = requestAudioFocus(l,
4050 new AudioAttributes.Builder()
4051 .setInternalLegacyStreamType(streamType).build(),
4052 durationHint,
4053 0 /* flags, legacy behavior */);
4054 } catch (IllegalArgumentException e) {
4055 Log.e(TAG, "Audio focus request denied due to ", e);
4056 }
4057
4058 return status;
4059 }
4060
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004061 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004062 /**
4063 * @hide
4064 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4065 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4066 * the system is in a state where focus cannot change, but be granted focus later when
4067 * this condition ends.
4068 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004069 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004070 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004071 /**
4072 * @hide
4073 * Use this flag when requesting audio focus to indicate that the requester
4074 * will pause its media playback (if applicable) when losing audio focus with
4075 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4076 * <br>On some platforms, the ducking may be handled without the application being aware of it
4077 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4078 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4079 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4080 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004081 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004082 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4083 /**
4084 * @hide
4085 * Use this flag to lock audio focus so granting is temporarily disabled.
4086 * <br>This flag can only be used by owners of a registered
4087 * {@link android.media.audiopolicy.AudioPolicy} in
4088 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4089 */
4090 @SystemApi
4091 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004092
4093 /**
4094 * @hide
4095 * flag set on test API calls,
4096 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004097 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004098 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004099 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004100 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4101 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004102 /** @hide */
4103 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004104 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004105
4106 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004107 * Request audio focus.
4108 * See the {@link AudioFocusRequest} for information about the options available to configure
4109 * your request, and notification of focus gain and loss.
4110 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4111 * requested.
4112 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4113 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4114 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4115 * is requested without building the {@link AudioFocusRequest} with
4116 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4117 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004118 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004119 */
4120 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004121 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004122 }
4123
4124 /**
4125 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4126 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4127 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4128 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4129 * @throws IllegalArgumentException if passed a null argument
4130 */
4131 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4132 if (focusRequest == null) {
4133 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4134 }
4135 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4136 focusRequest.getAudioAttributes());
4137 }
4138
4139 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004140 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004141 * Request audio focus.
4142 * Send a request to obtain the audio focus. This method differs from
4143 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4144 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004145 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4146 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4147 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4148 * requesting audio focus.
4149 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4150 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4151 * for the playback of driving directions, or notifications sounds.
4152 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4153 * the previous focus owner to keep playing if it ducks its audio output.
4154 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4155 * that benefits from the system not playing disruptive sounds like notifications, for
4156 * usecases such as voice memo recording, or speech recognition.
4157 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4158 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004159 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4160 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004161 * <br>Use 0 when not using any flags for the request, which behaves like
4162 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4163 * focus is granted immediately, or the grant request fails because the system is in a
4164 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004165 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4166 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4167 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4168 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4169 * @throws IllegalArgumentException
4170 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004171 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004172 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004173 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004174 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004175 int durationHint,
4176 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004177 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4178 throw new IllegalArgumentException("Invalid flags 0x"
4179 + Integer.toHexString(flags).toUpperCase());
4180 }
4181 return requestAudioFocus(l, requestAttributes, durationHint,
4182 flags & AUDIOFOCUS_FLAGS_APPS,
4183 null /* no AudioPolicy*/);
4184 }
4185
4186 /**
4187 * @hide
4188 * Request or lock audio focus.
4189 * This method is to be used by system components that have registered an
4190 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4191 * so focus granting is temporarily disabled.
4192 * @param l see the description of the same parameter in
4193 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4194 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4195 * requesting audio focus.
4196 * @param durationHint see the description of the same parameter in
4197 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4198 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004199 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004200 * <br>Use 0 when not using any flags for the request, which behaves like
4201 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4202 * focus is granted immediately, or the grant request fails because the system is in a
4203 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004204 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4205 * focus, or null.
4206 * @return see the description of the same return value in
4207 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4208 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004209 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004210 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004211 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004212 @RequiresPermission(anyOf= {
4213 android.Manifest.permission.MODIFY_PHONE_STATE,
4214 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4215 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004216 public int requestAudioFocus(OnAudioFocusChangeListener l,
4217 @NonNull AudioAttributes requestAttributes,
4218 int durationHint,
4219 int flags,
4220 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004221 // parameter checking
4222 if (requestAttributes == null) {
4223 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4224 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004225 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004226 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004227 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004228 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004229 throw new IllegalArgumentException("Illegal flags 0x"
4230 + Integer.toHexString(flags).toUpperCase());
4231 }
4232 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4233 throw new IllegalArgumentException(
4234 "Illegal null focus listener when flagged as accepting delayed focus grant");
4235 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004236 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4237 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4238 throw new IllegalArgumentException(
4239 "Illegal null focus listener when flagged as pausing instead of ducking");
4240 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004241 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4242 throw new IllegalArgumentException(
4243 "Illegal null audio policy when locking audio focus");
4244 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004245
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004246 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004247 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004248 .setAudioAttributes(requestAttributes)
4249 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4250 == AUDIOFOCUS_FLAG_DELAY_OK)
4251 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4252 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4253 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4254 .build();
4255 return requestAudioFocus(afr, ap);
4256 }
4257
4258 /**
4259 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004260 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4261 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4262 * @param afr the parameters of the request
4263 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4264 * @param clientFakeUid the UID of the client, here an arbitrary int,
4265 * doesn't have to be a real UID
4266 * @param clientTargetSdk the target SDK used by the client
4267 * @return return code indicating status of the request
4268 */
4269 @TestApi
4270 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4271 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4272 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4273 Objects.requireNonNull(afr);
4274 Objects.requireNonNull(clientFakeId);
4275 try {
4276 return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4277 afr.getFocusGain(),
4278 mICallBack,
4279 mAudioFocusDispatcher,
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004280 clientFakeId, "com.android.test.fakeclient",
4281 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4282 clientFakeUid, clientTargetSdk);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004283 } catch (RemoteException e) {
4284 throw e.rethrowFromSystemServer();
4285 }
4286 }
4287
4288 /**
4289 * @hide
4290 * Test API to abandon audio focus for an arbitrary client.
4291 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4292 * @param afr the parameters used for the request
4293 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4294 * would be requesting
4295 * @return return code indicating status of the request
4296 */
4297 @TestApi
4298 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4299 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4300 @NonNull String clientFakeId) {
4301 Objects.requireNonNull(afr);
4302 Objects.requireNonNull(clientFakeId);
4303 try {
4304 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4305 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4306 } catch (RemoteException e) {
4307 throw e.rethrowFromSystemServer();
4308 }
4309 }
4310
4311 /**
4312 * @hide
4313 * Return the duration of the fade out applied when a player of the given AudioAttributes
4314 * is losing audio focus
4315 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4316 * @return a duration in ms, 0 indicates no fade out is applied
4317 */
4318 @TestApi
4319 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4320 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4321 {
4322 Objects.requireNonNull(aa);
4323 try {
4324 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4325 } catch (RemoteException e) {
4326 throw e.rethrowFromSystemServer();
4327 }
4328 }
4329
4330 /**
4331 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004332 * Request or lock audio focus.
4333 * This method is to be used by system components that have registered an
4334 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4335 * so focus granting is temporarily disabled.
4336 * @param afr see the description of the same parameter in
4337 * {@link #requestAudioFocus(AudioFocusRequest)}
4338 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4339 * focus, or null.
4340 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4341 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4342 * @throws NullPointerException if the AudioFocusRequest is null
4343 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4344 */
4345 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004346 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004347 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4348 if (afr == null) {
4349 throw new NullPointerException("Illegal null AudioFocusRequest");
4350 }
4351 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4352 if (afr.locksFocus() && ap == null) {
4353 throw new IllegalArgumentException(
4354 "Illegal null audio policy when locking audio focus");
4355 }
4356 registerAudioFocusRequest(afr);
4357 final IAudioService service = getService();
4358 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004359 int sdk;
4360 try {
4361 sdk = getContext().getApplicationInfo().targetSdkVersion;
4362 } catch (NullPointerException e) {
4363 // some tests don't have a Context
4364 sdk = Build.VERSION.SDK_INT;
4365 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004366
4367 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4368 final BlockingFocusResultReceiver focusReceiver;
4369 synchronized (mFocusRequestsLock) {
4370 try {
4371 // TODO status contains result and generation counter for ext policy
4372 status = service.requestAudioFocus(afr.getAudioAttributes(),
4373 afr.getFocusGain(), mICallBack,
4374 mAudioFocusDispatcher,
4375 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004376 getContext().getOpPackageName() /* package name */,
4377 getContext().getAttributionTag(),
4378 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004379 ap != null ? ap.cb() : null,
4380 sdk);
4381 } catch (RemoteException e) {
4382 throw e.rethrowFromSystemServer();
4383 }
4384 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4385 // default path with no external focus policy
4386 return status;
4387 }
4388 if (mFocusRequestsAwaitingResult == null) {
4389 mFocusRequestsAwaitingResult =
4390 new HashMap<String, BlockingFocusResultReceiver>(1);
4391 }
4392 focusReceiver = new BlockingFocusResultReceiver(clientId);
4393 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004394 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004395 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4396 if (DEBUG && !focusReceiver.receivedResult()) {
4397 Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4398 }
4399 synchronized (mFocusRequestsLock) {
4400 mFocusRequestsAwaitingResult.remove(clientId);
4401 }
4402 return focusReceiver.requestResult();
4403 }
4404
4405 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4406 private static final class SafeWaitObject {
4407 private boolean mQuit = false;
4408
4409 public void safeNotify() {
4410 synchronized (this) {
4411 mQuit = true;
4412 this.notify();
4413 }
4414 }
4415
4416 public void safeWait(long millis) throws InterruptedException {
4417 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4418 synchronized (this) {
4419 while (!mQuit) {
4420 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4421 if (timeToWait < 0) { break; }
4422 this.wait(timeToWait);
4423 }
4424 }
4425 }
4426 }
4427
4428 private static final class BlockingFocusResultReceiver {
4429 private final SafeWaitObject mLock = new SafeWaitObject();
4430 @GuardedBy("mLock")
4431 private boolean mResultReceived = false;
4432 // request denied by default (e.g. timeout)
4433 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4434 private final String mFocusClientId;
4435
4436 BlockingFocusResultReceiver(String clientId) {
4437 mFocusClientId = clientId;
4438 }
4439
4440 boolean receivedResult() { return mResultReceived; }
4441 int requestResult() { return mFocusRequestResult; }
4442
4443 void notifyResult(int requestResult) {
4444 synchronized (mLock) {
4445 mResultReceived = true;
4446 mFocusRequestResult = requestResult;
4447 mLock.safeNotify();
4448 }
4449 }
4450
4451 public void waitForResult(long timeOutMs) {
4452 synchronized (mLock) {
4453 if (mResultReceived) {
4454 // the result was received before waiting
4455 return;
4456 }
4457 try {
4458 mLock.safeWait(timeOutMs);
4459 } catch (InterruptedException e) { }
4460 }
4461 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004462 }
4463
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004464 /**
4465 * @hide
4466 * Used internally by telephony package to request audio focus. Will cause the focus request
4467 * to be associated with the "voice communication" identifier only used in AudioService
4468 * to identify this use case.
4469 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4470 * the establishment of the call
4471 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4472 * media applications resume after a call
4473 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004474 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004475 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004476 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004477 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004478 service.requestAudioFocus(new AudioAttributes.Builder()
4479 .setInternalLegacyStreamType(streamType).build(),
4480 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004481 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004482 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004483 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004484 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004485 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004486 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004487 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004488 }
4489 }
4490
4491 /**
4492 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004493 * Return the volume ramping time for a sound to be played after the given focus request,
4494 * and to play a sound of the given attributes
4495 * @param focusGain
4496 * @param attr
4497 * @return
4498 */
4499 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004500 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004501 try {
4502 return service.getFocusRampTimeMs(focusGain, attr);
4503 } catch (RemoteException e) {
4504 throw e.rethrowFromSystemServer();
4505 }
4506 }
4507
4508 /**
4509 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004510 * Set the result to the audio focus request received through
4511 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4512 * @param afi the information about the focus requester
4513 * @param requestResult the result to the focus request to be passed to the requester
4514 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4515 */
4516 @SystemApi
4517 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4518 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4519 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4520 if (afi == null) {
4521 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4522 }
4523 if (ap == null) {
4524 throw new IllegalArgumentException("Illegal null AudioPolicy");
4525 }
4526 final IAudioService service = getService();
4527 try {
4528 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4529 } catch (RemoteException e) {
4530 throw e.rethrowFromSystemServer();
4531 }
4532 }
4533
4534 /**
4535 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004536 * Notifies an application with a focus listener of gain or loss of audio focus.
4537 * This method can only be used by owners of an {@link AudioPolicy} configured with
4538 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4539 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4540 * that was received by the {@code AudioPolicy} through
4541 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4542 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4543 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4544 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4545 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4546 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4547 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4548 * <br>For the focus gain, the change type should be the same as the app requested.
4549 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4550 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4551 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4552 * if there was an error sending the request.
4553 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4554 */
4555 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004556 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004557 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4558 @NonNull AudioPolicy ap) {
4559 if (afi == null) {
4560 throw new NullPointerException("Illegal null AudioFocusInfo");
4561 }
4562 if (ap == null) {
4563 throw new NullPointerException("Illegal null AudioPolicy");
4564 }
4565 final IAudioService service = getService();
4566 try {
4567 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4568 } catch (RemoteException e) {
4569 throw e.rethrowFromSystemServer();
4570 }
4571 }
4572
4573 /**
4574 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004575 * Used internally by telephony package to abandon audio focus, typically after a call or
4576 * when ringing ends and the call is rejected or not answered.
4577 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4578 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004579 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004580 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004581 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004582 try {
John Spurlock61560172015-02-06 19:46:04 -05004583 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004584 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004585 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004586 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004587 }
4588 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004589
4590 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004591 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4592 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004593 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004594 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004595 */
4596 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004597 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4598 }
4599
4600 /**
4601 * @hide
4602 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4603 * @param l the listener with which focus was requested.
4604 * @param aa the {@link AudioAttributes} with which audio focus was requested
4605 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004606 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004607 */
4608 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004609 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4610 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004611 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004612 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004613 unregisterAudioFocusRequest(l);
4614 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004615 try {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004616 status = service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004617 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004618 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004619 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004620 }
4621 return status;
4622 }
4623
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004624 //====================================================================
4625 // Remote Control
4626 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004627 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004628 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4629 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004630 * in the application manifest. The package of the component must match that of
4631 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004632 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004633 */
RoboErikb214efb2014-07-24 13:20:30 -07004634 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004635 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004636 if (eventReceiver == null) {
4637 return;
4638 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004639 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004640 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4641 "receiver and context package names don't match");
4642 return;
4643 }
4644 // construct a PendingIntent for the media button and register it
4645 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4646 // the associated intent will be handled by the component being registered
4647 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004648 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004649 0/*requestCode, ignored*/, mediaButtonIntent,
4650 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004651 registerMediaButtonIntent(pi, eventReceiver);
4652 }
4653
4654 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004655 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4656 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4657 * the buttons to go to any PendingIntent. Note that you should only use this form if
4658 * you know you will continue running for the full time until unregistering the
4659 * PendingIntent.
4660 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004661 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4662 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4663 * media button that was pressed.
4664 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004665 */
RoboErikb214efb2014-07-24 13:20:30 -07004666 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004667 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4668 if (eventReceiver == null) {
4669 return;
4670 }
4671 registerMediaButtonIntent(eventReceiver, null);
4672 }
4673
4674 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004675 * @hide
4676 * no-op if (pi == null) or (eventReceiver == null)
4677 */
4678 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004679 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004680 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4681 return;
4682 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004683 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4684 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004685 }
4686
4687 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004688 * Unregister the receiver of MEDIA_BUTTON intents.
4689 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4690 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004691 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004692 */
RoboErikb214efb2014-07-24 13:20:30 -07004693 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004694 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004695 if (eventReceiver == null) {
4696 return;
4697 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004698 // construct a PendingIntent for the media button and unregister it
4699 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4700 // the associated intent will be handled by the component being registered
4701 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004702 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004703 0/*requestCode, ignored*/, mediaButtonIntent,
4704 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004705 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004706 }
4707
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004708 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004709 * Unregister the receiver of MEDIA_BUTTON intents.
4710 * @param eventReceiver same PendingIntent that was registed with
4711 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004712 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004713 */
RoboErikb214efb2014-07-24 13:20:30 -07004714 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004715 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4716 if (eventReceiver == null) {
4717 return;
4718 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004719 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004720 }
4721
4722 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004723 * @hide
4724 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004725 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004726 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004727 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004728 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004729
4730 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004731 * Registers the remote control client for providing information to display on the remote
4732 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004733 * @param rcClient The remote control client from which remote controls will receive
4734 * information to display.
4735 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004736 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004737 */
RoboErikb214efb2014-07-24 13:20:30 -07004738 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004739 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004740 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004741 return;
4742 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004743 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004744 }
4745
4746 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004747 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004748 * remote controls.
4749 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004750 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004751 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004752 */
RoboErikb214efb2014-07-24 13:20:30 -07004753 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004754 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004755 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004756 return;
4757 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004758 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004759 }
4760
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004761 /**
RoboErika66c40b2014-08-15 15:21:41 -07004762 * Registers a {@link RemoteController} instance for it to receive media
4763 * metadata updates and playback state information from applications using
4764 * {@link RemoteControlClient}, and control their playback.
4765 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004766 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004767 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004768 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004769 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004770 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004771 * @return true if the {@link RemoteController} was successfully registered,
4772 * false if an error occurred, due to an internal system error, or
4773 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004774 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004775 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4776 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004777 */
RoboErikb214efb2014-07-24 13:20:30 -07004778 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004779 public boolean registerRemoteController(RemoteController rctlr) {
4780 if (rctlr == null) {
4781 return false;
4782 }
RoboErik430fc482014-06-12 15:49:20 -07004783 rctlr.startListeningToSessions();
4784 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004785 }
4786
4787 /**
RoboErika66c40b2014-08-15 15:21:41 -07004788 * Unregisters a {@link RemoteController}, causing it to no longer receive
4789 * media metadata and playback state information, and no longer be capable
4790 * of controlling playback.
4791 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004792 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004793 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004794 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4795 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004796 */
RoboErikb214efb2014-07-24 13:20:30 -07004797 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004798 public void unregisterRemoteController(RemoteController rctlr) {
4799 if (rctlr == null) {
4800 return;
4801 }
RoboErik430fc482014-06-12 15:49:20 -07004802 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004803 }
4804
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004805
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004806 //====================================================================
4807 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004808 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004809 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004810 * Register the given {@link AudioPolicy}.
4811 * This call is synchronous and blocks until the registration process successfully completed
4812 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004813 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004814 * @return {@link #ERROR} if there was an error communicating with the registration service
4815 * or if the user doesn't have the required
4816 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4817 * {@link #SUCCESS} otherwise.
4818 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004819 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004820 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004821 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004822 return registerAudioPolicyStatic(policy);
4823 }
4824
4825 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004826 if (policy == null) {
4827 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4828 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004829 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004830 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004831 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004832 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07004833 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4834 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004835 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004836 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004837 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004838 } else {
4839 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004840 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004841 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004842 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004843 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004844 }
4845 return SUCCESS;
4846 }
4847
4848 /**
4849 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004850 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004851 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004852 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004853 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004854 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004855 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004856 unregisterAudioPolicyAsyncStatic(policy);
4857 }
4858
4859 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004860 if (policy == null) {
4861 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4862 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004863 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004864 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004865 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004866 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004867 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004868 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004869 }
4870 }
4871
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004872 /**
4873 * @hide
4874 * Unregisters an {@link AudioPolicy} synchronously.
4875 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4876 * associated with mixes of this policy.
4877 * @param policy the non-null {@link AudioPolicy} to unregister.
4878 */
4879 @SystemApi
4880 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4881 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4882 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4883 final IAudioService service = getService();
4884 try {
4885 policy.invalidateCaptorsAndInjectors();
4886 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004887 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004888 } catch (RemoteException e) {
4889 throw e.rethrowFromSystemServer();
4890 }
4891 }
4892
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07004893 /**
4894 * @hide
4895 * @return true if an AudioPolicy was previously registered
4896 */
4897 @TestApi
4898 public boolean hasRegisteredDynamicPolicy() {
4899 final IAudioService service = getService();
4900 try {
4901 return service.hasRegisteredDynamicPolicy();
4902 } catch (RemoteException e) {
4903 throw e.rethrowFromSystemServer();
4904 }
4905 }
4906
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004907 //====================================================================
4908 // Notification of playback activity & playback configuration
4909 /**
4910 * Interface for receiving update notifications about the playback activity on the system.
4911 * Extend this abstract class and register it with
4912 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4913 * to be notified.
4914 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4915 * configuration.
4916 * @see AudioPlaybackConfiguration
4917 */
4918 public static abstract class AudioPlaybackCallback {
4919 /**
4920 * Called whenever the playback activity and configuration has changed.
4921 * @param configs list containing the results of
4922 * {@link AudioManager#getActivePlaybackConfigurations()}.
4923 */
4924 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4925 }
4926
4927 private static class AudioPlaybackCallbackInfo {
4928 final AudioPlaybackCallback mCb;
4929 final Handler mHandler;
4930 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4931 mCb = cb;
4932 mHandler = handler;
4933 }
4934 }
4935
4936 private final static class PlaybackConfigChangeCallbackData {
4937 final AudioPlaybackCallback mCb;
4938 final List<AudioPlaybackConfiguration> mConfigs;
4939
4940 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4941 List<AudioPlaybackConfiguration> configs) {
4942 mCb = cb;
4943 mConfigs = configs;
4944 }
4945 }
4946
4947 /**
4948 * Register a callback to be notified of audio playback changes through
4949 * {@link AudioPlaybackCallback}
4950 * @param cb non-null callback to register
4951 * @param handler the {@link Handler} object for the thread on which to execute
4952 * the callback. If <code>null</code>, the {@link Handler} associated with the main
4953 * {@link Looper} will be used.
4954 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08004955 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4956 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004957 {
4958 if (cb == null) {
4959 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4960 }
4961
4962 synchronized(mPlaybackCallbackLock) {
4963 // lazy initialization of the list of playback callbacks
4964 if (mPlaybackCallbackList == null) {
4965 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4966 }
4967 final int oldCbCount = mPlaybackCallbackList.size();
4968 if (!hasPlaybackCallback_sync(cb)) {
4969 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4970 new ServiceEventHandlerDelegate(handler).getHandler()));
4971 final int newCbCount = mPlaybackCallbackList.size();
4972 if ((oldCbCount == 0) && (newCbCount > 0)) {
4973 // register binder for callbacks
4974 try {
4975 getService().registerPlaybackCallback(mPlayCb);
4976 } catch (RemoteException e) {
4977 throw e.rethrowFromSystemServer();
4978 }
4979 }
4980 } else {
4981 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4982 + "registered callback");
4983 }
4984 }
4985 }
4986
4987 /**
4988 * Unregister an audio playback callback previously registered with
4989 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4990 * @param cb non-null callback to unregister
4991 */
4992 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4993 if (cb == null) {
4994 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4995 }
4996 synchronized(mPlaybackCallbackLock) {
4997 if (mPlaybackCallbackList == null) {
4998 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4999 + " that was never registered");
5000 return;
5001 }
5002 final int oldCbCount = mPlaybackCallbackList.size();
5003 if (removePlaybackCallback_sync(cb)) {
5004 final int newCbCount = mPlaybackCallbackList.size();
5005 if ((oldCbCount > 0) && (newCbCount == 0)) {
5006 // unregister binder for callbacks
5007 try {
5008 getService().unregisterPlaybackCallback(mPlayCb);
5009 } catch (RemoteException e) {
5010 throw e.rethrowFromSystemServer();
5011 }
5012 }
5013 } else {
5014 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5015 + " already unregistered or never registered");
5016 }
5017 }
5018 }
5019
5020 /**
5021 * Returns the current active audio playback configurations of the device
5022 * @return a non-null list of playback configurations. An empty list indicates there is no
5023 * playback active when queried.
5024 * @see AudioPlaybackConfiguration
5025 */
5026 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5027 final IAudioService service = getService();
5028 try {
5029 return service.getActivePlaybackConfigurations();
5030 } catch (RemoteException e) {
5031 throw e.rethrowFromSystemServer();
5032 }
5033 }
5034
5035 /**
5036 * All operations on this list are sync'd on mPlaybackCallbackLock.
5037 * List is lazy-initialized in
5038 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5039 * List can be null.
5040 */
5041 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5042 private final Object mPlaybackCallbackLock = new Object();
5043
5044 /**
5045 * Must be called synchronized on mPlaybackCallbackLock
5046 */
5047 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5048 if (mPlaybackCallbackList != null) {
5049 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5050 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5051 return true;
5052 }
5053 }
5054 }
5055 return false;
5056 }
5057
5058 /**
5059 * Must be called synchronized on mPlaybackCallbackLock
5060 */
5061 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5062 if (mPlaybackCallbackList != null) {
5063 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5064 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5065 mPlaybackCallbackList.remove(i);
5066 return true;
5067 }
5068 }
5069 }
5070 return false;
5071 }
5072
5073 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005074 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005075 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5076 boolean flush) {
5077 if (flush) {
5078 Binder.flushPendingCommands();
5079 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005080 synchronized(mPlaybackCallbackLock) {
5081 if (mPlaybackCallbackList != null) {
5082 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5083 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5084 if (arci.mHandler != null) {
5085 final Message m = arci.mHandler.obtainMessage(
5086 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5087 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5088 arci.mHandler.sendMessage(m);
5089 }
5090 }
5091 }
5092 }
5093 }
5094
5095 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005096
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005097 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005098 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005099 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005100 * Interface for receiving update notifications about the recording configuration. Extend
5101 * this abstract class and register it with
5102 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5103 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005104 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5105 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005106 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005107 */
5108 public static abstract class AudioRecordingCallback {
5109 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005110 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005111 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005112 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005113 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005114 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005115 }
5116
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005117 private static class AudioRecordingCallbackInfo {
5118 final AudioRecordingCallback mCb;
5119 final Handler mHandler;
5120 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5121 mCb = cb;
5122 mHandler = handler;
5123 }
5124 }
5125
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005126 private final static class RecordConfigChangeCallbackData {
5127 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005128 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005129
5130 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005131 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005132 mCb = cb;
5133 mConfigs = configs;
5134 }
5135 }
5136
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005137 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005138 * Register a callback to be notified of audio recording changes through
5139 * {@link AudioRecordingCallback}
5140 * @param cb non-null callback to register
5141 * @param handler the {@link Handler} object for the thread on which to execute
5142 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5143 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005144 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005145 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5146 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005147 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005148 if (cb == null) {
5149 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5150 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005151
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005152 synchronized(mRecordCallbackLock) {
5153 // lazy initialization of the list of recording callbacks
5154 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005155 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005156 }
5157 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005158 if (!hasRecordCallback_sync(cb)) {
5159 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5160 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005161 final int newCbCount = mRecordCallbackList.size();
5162 if ((oldCbCount == 0) && (newCbCount > 0)) {
5163 // register binder for callbacks
5164 final IAudioService service = getService();
5165 try {
5166 service.registerRecordingCallback(mRecCb);
5167 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005168 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005169 }
5170 }
5171 } else {
5172 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5173 + "registered callback");
5174 }
5175 }
5176 }
5177
5178 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005179 * Unregister an audio recording callback previously registered with
5180 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5181 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005182 */
5183 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5184 if (cb == null) {
5185 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5186 }
5187 synchronized(mRecordCallbackLock) {
5188 if (mRecordCallbackList == null) {
5189 return;
5190 }
5191 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005192 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005193 final int newCbCount = mRecordCallbackList.size();
5194 if ((oldCbCount > 0) && (newCbCount == 0)) {
5195 // unregister binder for callbacks
5196 final IAudioService service = getService();
5197 try {
5198 service.unregisterRecordingCallback(mRecCb);
5199 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005200 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005201 }
5202 }
5203 } else {
5204 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5205 + " already unregistered or never registered");
5206 }
5207 }
5208 }
5209
5210 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005211 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005212 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005213 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005214 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005215 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005216 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005217 final IAudioService service = getService();
5218 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005219 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005220 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005221 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005222 }
5223 }
5224
5225 /**
5226 * constants for the recording events, to keep in sync
5227 * with frameworks/av/include/media/AudioPolicy.h
5228 */
5229 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005230 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005231 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005232 public static final int RECORD_CONFIG_EVENT_START = 0;
5233 /** @hide */
5234 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5235 /** @hide */
5236 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5237 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005238 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005239 /**
5240 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5241 */
5242 /** @hide */
5243 public static final int RECORD_RIID_INVALID = -1;
5244 /** @hide */
5245 public static final int RECORDER_STATE_STARTED = 0;
5246 /** @hide */
5247 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005248
5249 /**
5250 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005251 * List is lazy-initialized in
5252 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005253 * List can be null.
5254 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005255 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005256 private final Object mRecordCallbackLock = new Object();
5257
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005258 /**
5259 * Must be called synchronized on mRecordCallbackLock
5260 */
5261 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5262 if (mRecordCallbackList != null) {
5263 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5264 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5265 return true;
5266 }
5267 }
5268 }
5269 return false;
5270 }
5271
5272 /**
5273 * Must be called synchronized on mRecordCallbackLock
5274 */
5275 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5276 if (mRecordCallbackList != null) {
5277 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5278 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5279 mRecordCallbackList.remove(i);
5280 return true;
5281 }
5282 }
5283 }
5284 return false;
5285 }
5286
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005287 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005288 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005289 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005290 synchronized(mRecordCallbackLock) {
5291 if (mRecordCallbackList != null) {
5292 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5293 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5294 if (arci.mHandler != null) {
5295 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005296 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5297 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005298 arci.mHandler.sendMessage(m);
5299 }
5300 }
5301 }
5302 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005303 }
5304
5305 };
5306
5307 //=====================================================================
5308
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005309 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005310 * @hide
5311 * Reload audio settings. This method is called by Settings backup
5312 * agent when audio settings are restored and causes the AudioService
5313 * to read and apply restored settings.
5314 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005315 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005316 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005317 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005318 try {
5319 service.reloadAudioSettings();
5320 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005321 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005322 }
5323 }
5324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005325 /**
5326 * {@hide}
5327 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005328 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005329
5330 /**
5331 * Checks whether the phone is in silent mode, with or without vibrate.
5332 *
5333 * @return true if phone is in silent mode, with or without vibrate.
5334 *
5335 * @see #getRingerMode()
5336 *
5337 * @hide pending API Council approval
5338 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005339 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005340 public boolean isSilentMode() {
5341 int ringerMode = getRingerMode();
5342 boolean silentMode =
5343 (ringerMode == RINGER_MODE_SILENT) ||
5344 (ringerMode == RINGER_MODE_VIBRATE);
5345 return silentMode;
5346 }
5347
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005348 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5349 // class is not used by other parts of the framework, which instead use definitions and methods
5350 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5351
Eric Laurent948d3272014-05-16 15:18:45 -07005352 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005353 * The audio device code for representing "no device." */
5354 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5355 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005356 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005357 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5358 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5359 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5360 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005361 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005362 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005363 /** @hide
5364 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005365 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005366 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005367 /** @hide
5368 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005369 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005370 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005371 /** @hide
5372 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005373 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005374 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005375 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005376 * The audio output device code for a USB headphone with attached microphone */
5377 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5378 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005379 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005380 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005381 /** @hide
5382 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5383 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005384 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005385 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005386 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5387 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005388 /** @hide
5389 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005390 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5391 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005392 /** @hide
5393 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005394 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005395 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005396 /** @hide
5397 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005398 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005399 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5400 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005401 /** @hide
5402 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005403 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005404 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5405 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005406 /** @hide
5407 * The audio output device code for S/PDIF (legacy) or HDMI
5408 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005409 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005410 /** @hide
5411 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005412 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005413 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5414 /** @hide
5415 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005416 * docking station
5417 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005418 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005419 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005420 /** @hide
5421 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005422 * docking station
5423 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005424 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005425 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005426 /** @hide
5427 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005428 * mode and the Android device in USB device mode
5429 */
5430 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005431 /** @hide
5432 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005433 * mode and the Android device in USB host mode
5434 */
5435 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005436 /** @hide
5437 * The audio output device code for projection output.
5438 */
5439 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5440 /** @hide
5441 * The audio output device code the telephony voice TX path.
5442 */
5443 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5444 /** @hide
5445 * The audio output device code for an analog jack with line impedance detected.
5446 */
5447 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5448 /** @hide
5449 * The audio output device code for HDMI Audio Return Channel.
5450 */
5451 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5452 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005453 * The audio output device code for HDMI enhanced Audio Return Channel.
5454 */
5455 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5456 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005457 * The audio output device code for S/PDIF digital connection.
5458 */
5459 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5460 /** @hide
5461 * The audio output device code for built-in FM transmitter.
5462 */
5463 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5464 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005465 * The audio output device code for echo reference injection point.
5466 */
5467 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5468 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005469 * The audio output device code for a BLE audio headset.
5470 */
5471 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5472 /** @hide
5473 * The audio output device code for a BLE audio speaker.
5474 */
5475 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5476 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01005477 * The audio output device code for a BLE audio brodcast group.
5478 */
5479 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
5480 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005481 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005482 * used in the future in a set method to select whatever default device is chosen by the
5483 * platform-specific implementation.
5484 */
5485 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5486
Eric Laurent948d3272014-05-16 15:18:45 -07005487 /** @hide
5488 * The audio input device code for default built-in microphone
5489 */
5490 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5491 /** @hide
5492 * The audio input device code for a Bluetooth SCO headset
5493 */
5494 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5495 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5496 /** @hide
5497 * The audio input device code for wired headset microphone
5498 */
5499 public static final int DEVICE_IN_WIRED_HEADSET =
5500 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5501 /** @hide
5502 * The audio input device code for HDMI
5503 */
5504 public static final int DEVICE_IN_HDMI =
5505 AudioSystem.DEVICE_IN_HDMI;
5506 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005507 * The audio input device code for HDMI ARC
5508 */
5509 public static final int DEVICE_IN_HDMI_ARC =
5510 AudioSystem.DEVICE_IN_HDMI_ARC;
5511
5512 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005513 * The audio input device code for HDMI EARC
5514 */
5515 public static final int DEVICE_IN_HDMI_EARC =
5516 AudioSystem.DEVICE_IN_HDMI_EARC;
5517
5518 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005519 * The audio input device code for telephony voice RX path
5520 */
5521 public static final int DEVICE_IN_TELEPHONY_RX =
5522 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5523 /** @hide
5524 * The audio input device code for built-in microphone pointing to the back
5525 */
5526 public static final int DEVICE_IN_BACK_MIC =
5527 AudioSystem.DEVICE_IN_BACK_MIC;
5528 /** @hide
5529 * The audio input device code for analog from a docking station
5530 */
5531 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5532 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5533 /** @hide
5534 * The audio input device code for digital from a docking station
5535 */
5536 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5537 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5538 /** @hide
5539 * The audio input device code for a USB audio accessory. The accessory is in USB host
5540 * mode and the Android device in USB device mode
5541 */
5542 public static final int DEVICE_IN_USB_ACCESSORY =
5543 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5544 /** @hide
5545 * The audio input device code for a USB audio device. The device is in USB device
5546 * mode and the Android device in USB host mode
5547 */
5548 public static final int DEVICE_IN_USB_DEVICE =
5549 AudioSystem.DEVICE_IN_USB_DEVICE;
5550 /** @hide
5551 * The audio input device code for a FM radio tuner
5552 */
5553 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5554 /** @hide
5555 * The audio input device code for a TV tuner
5556 */
5557 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5558 /** @hide
5559 * The audio input device code for an analog jack with line impedance detected
5560 */
5561 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5562 /** @hide
5563 * The audio input device code for a S/PDIF digital connection
5564 */
5565 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005566 /** @hide
5567 * The audio input device code for audio loopback
5568 */
5569 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005570 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005571 * The audio input device code for an echo reference capture point.
5572 */
5573 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5574 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005575 * The audio input device code for a BLE audio headset.
5576 */
5577 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005578
5579 /**
5580 * Return true if the device code corresponds to an output device.
5581 * @hide
5582 */
5583 public static boolean isOutputDevice(int device)
5584 {
5585 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5586 }
5587
5588 /**
5589 * Return true if the device code corresponds to an input device.
5590 * @hide
5591 */
5592 public static boolean isInputDevice(int device)
5593 {
5594 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5595 }
5596
5597
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005598 /**
5599 * Return the enabled devices for the specified output stream type.
5600 *
5601 * @param streamType The stream type to query. One of
5602 * {@link #STREAM_VOICE_CALL},
5603 * {@link #STREAM_SYSTEM},
5604 * {@link #STREAM_RING},
5605 * {@link #STREAM_MUSIC},
5606 * {@link #STREAM_ALARM},
5607 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005608 * {@link #STREAM_DTMF},
5609 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005610 *
5611 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5612 * stream. Zero or more of
5613 * {@link #DEVICE_OUT_EARPIECE},
5614 * {@link #DEVICE_OUT_SPEAKER},
5615 * {@link #DEVICE_OUT_WIRED_HEADSET},
5616 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5617 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5618 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5619 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5620 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5621 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5622 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005623 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005624 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5625 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005626 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5627 * {@link #DEVICE_OUT_USB_DEVICE}.
5628 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5629 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5630 * {@link #DEVICE_OUT_LINE}.
5631 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005632 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005633 * {@link #DEVICE_OUT_SPDIF}.
5634 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005635 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5636 *
5637 * The implementation may support additional device codes beyond those listed, so
5638 * the application should ignore any bits which it does not recognize.
5639 * Note that the information may be imprecise when the implementation
5640 * cannot distinguish whether a particular device is enabled.
5641 *
Andy Hungb11e4c72021-04-13 19:31:00 -07005642 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
5643 * will have multi-bit device types.
5644 * Prefer to use {@link #getDevicesForAttributes()} instead,
5645 * noting that getDevicesForStream() has a few small discrepancies
5646 * for better volume handling.
5647 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005648 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005649 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07005650 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005651 public int getDevicesForStream(int streamType) {
5652 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07005653 case STREAM_VOICE_CALL:
5654 case STREAM_SYSTEM:
5655 case STREAM_RING:
5656 case STREAM_MUSIC:
5657 case STREAM_ALARM:
5658 case STREAM_NOTIFICATION:
5659 case STREAM_DTMF:
5660 case STREAM_ACCESSIBILITY:
5661 final IAudioService service = getService();
5662 try {
5663 return service.getDeviceMaskForStream(streamType);
5664 } catch (RemoteException e) {
5665 throw e.rethrowFromSystemServer();
5666 }
5667 default:
5668 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005669 }
5670 }
5671
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005672 /**
5673 * @hide
5674 * Get the audio devices that would be used for the routing of the given audio attributes.
5675 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5676 * @return an empty list if there was an issue with the request, a list of audio devices
5677 * otherwise (typically one device, except for duplicated paths).
5678 */
5679 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005680 @RequiresPermission(anyOf = {
5681 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5682 android.Manifest.permission.QUERY_AUDIO_STATE
5683 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005684 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005685 @NonNull AudioAttributes attributes) {
5686 Objects.requireNonNull(attributes);
5687 final IAudioService service = getService();
5688 try {
5689 return service.getDevicesForAttributes(attributes);
5690 } catch (RemoteException e) {
5691 throw e.rethrowFromSystemServer();
5692 }
5693 }
5694
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005695 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01005696 * Get the audio devices that would be used for the routing of the given audio attributes.
5697 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
5698 * the specified {@link AudioAttributes}.
5699 * The audio routing can change if audio devices are physically connected or disconnected or
5700 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
5701 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5702 * @return an empty list if there was an issue with the request, a list of
5703 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
5704 */
5705 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
5706 @NonNull AudioAttributes attributes) {
5707 final List<AudioDeviceAttributes> devicesForAttributes;
5708 try {
5709 Objects.requireNonNull(attributes);
5710 final IAudioService service = getService();
5711 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
5712 } catch (Exception e) {
5713 Log.i(TAG, "No audio devices available for specified attributes.");
5714 return Collections.emptyList();
5715 }
5716
5717 // Map from AudioDeviceAttributes to AudioDeviceInfo
5718 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
5719 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
5720 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
5721 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
5722 if (deviceForAttributes.getType() == deviceInfo.getType()
5723 && TextUtils.equals(deviceForAttributes.getAddress(),
5724 deviceInfo.getAddress())) {
5725 deviceInfosForAttributes.add(deviceInfo);
5726 }
5727 }
5728 }
5729 return Collections.unmodifiableList(deviceInfosForAttributes);
5730 }
5731
5732 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005733 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005734 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02005735 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5736 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005737 */
5738 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5739 /**
5740 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005741 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02005742 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005743 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005744 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005745 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5746 /**
5747 * @hide
5748 * Volume behavior for an audio device where the volume is always set to provide no attenuation
5749 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005750 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005751 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005752 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005753 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5754 /**
5755 * @hide
5756 * Volume behavior for an audio device where the volume is either set to muted, or to provide
5757 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005758 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005759 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005760 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005761 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5762 /**
5763 * @hide
5764 * Volume behavior for an audio device where no software attenuation is applied, and
5765 * the volume is kept synchronized between the host and the device itself through a
5766 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005767 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005768 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005769 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005770 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5771 /**
5772 * @hide
5773 * Volume behavior for an audio device where no software attenuation is applied, and
5774 * the volume is kept synchronized between the host and the device itself through a
5775 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5776 * normal vs in phone call).
5777 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02005778 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005779 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005780 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005781 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5782
5783 /** @hide */
5784 @IntDef({
5785 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5786 DEVICE_VOLUME_BEHAVIOR_FULL,
5787 DEVICE_VOLUME_BEHAVIOR_FIXED,
5788 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5789 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5790 })
5791 @Retention(RetentionPolicy.SOURCE)
5792 public @interface DeviceVolumeBehavior {}
5793
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005794 /** @hide */
5795 @IntDef({
5796 DEVICE_VOLUME_BEHAVIOR_UNSET,
5797 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5798 DEVICE_VOLUME_BEHAVIOR_FULL,
5799 DEVICE_VOLUME_BEHAVIOR_FIXED,
5800 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5801 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5802 })
5803 @Retention(RetentionPolicy.SOURCE)
5804 public @interface DeviceVolumeBehaviorState {}
5805
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005806 /**
5807 * @hide
5808 * Throws IAE on an invalid volume behavior value
5809 * @param volumeBehavior behavior value to check
5810 */
5811 public static void enforceValidVolumeBehavior(int volumeBehavior) {
5812 switch (volumeBehavior) {
5813 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5814 case DEVICE_VOLUME_BEHAVIOR_FULL:
5815 case DEVICE_VOLUME_BEHAVIOR_FIXED:
5816 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5817 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5818 return;
5819 default:
5820 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5821 }
5822 }
5823
5824 /**
5825 * @hide
5826 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005827 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5828 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5829 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5830 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5831 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5832 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005833 * @param deviceVolumeBehavior one of the device behaviors
5834 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005835 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005836 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5837 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5838 @DeviceVolumeBehavior int deviceVolumeBehavior) {
5839 // verify arguments (validity of device type is enforced in server)
5840 Objects.requireNonNull(device);
5841 enforceValidVolumeBehavior(deviceVolumeBehavior);
5842 // communicate with service
5843 final IAudioService service = getService();
5844 try {
5845 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5846 mApplicationContext.getOpPackageName());
5847 } catch (RemoteException e) {
5848 throw e.rethrowFromSystemServer();
5849 }
5850 }
5851
5852 /**
5853 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005854 * Returns the volume device behavior for the given audio device
5855 * @param device the audio device
5856 * @return the volume behavior for the device
5857 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005858 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005859 @RequiresPermission(anyOf = {
5860 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5861 android.Manifest.permission.QUERY_AUDIO_STATE
5862 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02005863 public @DeviceVolumeBehavior
5864 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005865 // verify arguments (validity of device type is enforced in server)
5866 Objects.requireNonNull(device);
5867 // communicate with service
5868 final IAudioService service = getService();
5869 try {
5870 return service.getDeviceVolumeBehavior(device);
5871 } catch (RemoteException e) {
5872 throw e.rethrowFromSystemServer();
5873 }
5874 }
5875
kholoud mohamed37839212021-03-15 16:49:06 +00005876 /**
5877 * @hide
5878 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5879 */
5880 @TestApi
5881 @RequiresPermission(anyOf = {
5882 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5883 android.Manifest.permission.QUERY_AUDIO_STATE
5884 })
5885 public boolean isFullVolumeDevice() {
5886 final AudioAttributes attributes = new AudioAttributes.Builder()
5887 .setUsage(AudioAttributes.USAGE_MEDIA)
5888 .build();
5889 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5890 for (AudioDeviceAttributes device : devices) {
5891 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5892 return true;
5893 }
5894 }
5895 return false;
5896 }
5897
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005898 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005899 * Indicate wired accessory connection state change.
5900 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5901 * @param state new connection state: 1 connected, 0 disconnected
5902 * @param name device name
5903 * {@hide}
5904 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005905 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07005906 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair7b72c392022-04-04 13:25:46 +02005907 public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
5908 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005909 setWiredDeviceConnectionState(attributes, state);
5910 }
5911
5912 /**
5913 * Indicate wired accessory connection state change and attributes.
5914 * @param state new connection state: 1 connected, 0 disconnected
5915 * @param attributes attributes of the connected device
5916 * {@hide}
5917 */
5918 @UnsupportedAppUsage
5919 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5920 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005921 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005922 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005923 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07005924 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005925 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005926 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005927 }
5928 }
5929
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00005930 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08005931 * Indicate wired accessory connection state change.
5932 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
5933 * @param connected true for connected, false for disconnected
5934 * {@hide}
5935 */
5936 @TestApi
5937 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5938 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
5939 boolean connected) {
5940 try {
5941 getService().setTestDeviceConnectionState(device, connected);
5942 } catch (RemoteException e) {
5943 throw e.rethrowFromSystemServer();
5944 }
5945 }
5946
5947 /**
wescande7c17ba0c2021-07-30 16:46:14 +02005948 * Indicate Bluetooth profile connection state change.
5949 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
5950 * <code>previousDevice</code>
5951 * This operation is asynchronous.
5952 *
5953 * @param newDevice Bluetooth device connected or null if there is no new devices
5954 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
5955 * devices
William Escandeac11d772022-01-25 18:01:15 +01005956 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005957 * {@hide}
5958 */
wescande7c17ba0c2021-07-30 16:46:14 +02005959 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5960 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
5961 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01005962 @Nullable BluetoothDevice previousDevice,
5963 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005964 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005965 try {
wescande7c17ba0c2021-07-30 16:46:14 +02005966 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005967 } catch (RemoteException e) {
5968 throw e.rethrowFromSystemServer();
5969 }
5970 }
5971
Jeff Sharkey098d5802012-04-26 17:30:34 -07005972 /** {@hide} */
5973 public IRingtonePlayer getRingtonePlayer() {
5974 try {
5975 return getService().getRingtonePlayer();
5976 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005977 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005978 }
5979 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005980
5981 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005982 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07005983 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
5984 * should use this value as a default, and offer the user the option to override it.
5985 * The low latency output stream is typically either the device's primary output stream,
5986 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005987 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005988 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005989 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5990 "android.media.property.OUTPUT_SAMPLE_RATE";
5991
5992 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005993 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07005994 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
5995 * should use this value as a minimum, and offer the user the option to override it.
5996 * The low latency output stream is typically either the device's primary output stream,
5997 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005998 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005999 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07006000 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
6001 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
6002
6003 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07006004 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
6005 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6006 */
6007 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6008 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6009
6010 /**
6011 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6012 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6013 */
6014 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6015 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6016
6017 /**
ragoa7cc59c2015-12-02 11:31:15 -08006018 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6019 * available and supported with the expected frequency range and level response.
6020 */
6021 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6022 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6023 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006024 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006025 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006026 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6027 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006028 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6029 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6030 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006031 * @return A string representing the associated value for that property key,
6032 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006033 */
6034 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006035 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6036 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6037 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6038 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6039 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6040 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006041 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006042 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6043 // not found.
6044 return String.valueOf(getContext().getResources().getBoolean(
6045 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006046 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006047 return String.valueOf(getContext().getResources().getBoolean(
6048 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006049 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6050 return String.valueOf(getContext().getResources().getBoolean(
6051 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006052 } else {
6053 // null or unknown key
6054 return null;
6055 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006056 }
6057
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006058 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006059 * @hide
6060 * Sets an additional audio output device delay in milliseconds.
6061 *
6062 * The additional output delay is a request to the output device to
6063 * delay audio presentation (generally with respect to video presentation for better
6064 * synchronization).
6065 * It may not be supported by all output devices,
6066 * and typically increases the audio latency by the amount of additional
6067 * audio delay requested.
6068 *
6069 * If additional audio delay is supported by an audio output device,
6070 * it is expected to be supported for all output streams (and configurations)
6071 * opened on that device.
6072 *
6073 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006074 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006075 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6076 * @return true if successful, false if the device does not support output device delay
6077 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6078 */
6079 @SystemApi
6080 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6081 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006082 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006083 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006084 try {
6085 return getService().setAdditionalOutputDeviceDelay(
6086 new AudioDeviceAttributes(device), delayMillis);
6087 } catch (RemoteException e) {
6088 throw e.rethrowFromSystemServer();
6089 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006090 }
6091
6092 /**
6093 * @hide
6094 * Returns the current additional audio output device delay in milliseconds.
6095 *
6096 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6097 * @return the additional output device delay. This is a non-negative number.
6098 * {@code 0} is returned if unsupported.
6099 */
6100 @SystemApi
6101 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006102 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006103 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006104 try {
6105 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6106 } catch (RemoteException e) {
6107 throw e.rethrowFromSystemServer();
6108 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006109 }
6110
6111 /**
6112 * @hide
6113 * Returns the maximum additional audio output device delay in milliseconds.
6114 *
6115 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6116 * @return the maximum output device delay in milliseconds that can be set.
6117 * This is a non-negative number
6118 * representing the additional audio delay supported for the device.
6119 * {@code 0} is returned if unsupported.
6120 */
6121 @SystemApi
6122 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006123 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006124 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006125 try {
6126 return getService().getMaxAdditionalOutputDeviceDelay(
6127 new AudioDeviceAttributes(device));
6128 } catch (RemoteException e) {
6129 throw e.rethrowFromSystemServer();
6130 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006131 }
6132
6133 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006134 * Returns the estimated latency for the given stream type in milliseconds.
6135 *
6136 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6137 * a better solution.
6138 * @hide
6139 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006140 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006141 public int getOutputLatency(int streamType) {
6142 return AudioSystem.getOutputLatency(streamType);
6143 }
6144
John Spurlock3346a802014-05-20 16:25:37 -04006145 /**
6146 * Registers a global volume controller interface. Currently limited to SystemUI.
6147 *
6148 * @hide
6149 */
6150 public void setVolumeController(IVolumeController controller) {
6151 try {
6152 getService().setVolumeController(controller);
6153 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006154 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006155 }
6156 }
6157
6158 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006159 * Notify audio manager about volume controller visibility changes.
6160 * Currently limited to SystemUI.
6161 *
6162 * @hide
6163 */
6164 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6165 try {
6166 getService().notifyVolumeControllerVisible(controller, visible);
6167 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006168 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006169 }
6170 }
6171
6172 /**
John Spurlock3346a802014-05-20 16:25:37 -04006173 * Only useful for volume controllers.
6174 * @hide
6175 */
John Spurlock3346a802014-05-20 16:25:37 -04006176 public boolean isStreamAffectedByRingerMode(int streamType) {
6177 try {
6178 return getService().isStreamAffectedByRingerMode(streamType);
6179 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006180 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006181 }
6182 }
6183
6184 /**
6185 * Only useful for volume controllers.
6186 * @hide
6187 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006188 public boolean isStreamAffectedByMute(int streamType) {
6189 try {
6190 return getService().isStreamAffectedByMute(streamType);
6191 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006192 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006193 }
6194 }
6195
6196 /**
6197 * Only useful for volume controllers.
6198 * @hide
6199 */
John Spurlock3346a802014-05-20 16:25:37 -04006200 public void disableSafeMediaVolume() {
6201 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006202 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006203 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006204 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006205 }
6206 }
Eric Laurenta198a292014-02-18 16:26:17 -08006207
6208 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006209 * Only useful for volume controllers.
6210 * @hide
6211 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006212 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006213 public void setRingerModeInternal(int ringerMode) {
6214 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006215 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006216 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006217 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006218 }
6219 }
6220
6221 /**
6222 * Only useful for volume controllers.
6223 * @hide
6224 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006225 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006226 public int getRingerModeInternal() {
6227 try {
6228 return getService().getRingerModeInternal();
6229 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006230 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006231 }
6232 }
6233
6234 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006235 * Only useful for volume controllers.
6236 * @hide
6237 */
6238 public void setVolumePolicy(VolumePolicy policy) {
6239 try {
6240 getService().setVolumePolicy(policy);
6241 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006242 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006243 }
6244 }
6245
6246 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006247 * Set Hdmi Cec system audio mode.
6248 *
6249 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006250 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006251 * @hide
6252 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006253 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006254 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006255 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006256 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006257 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006258 }
6259 }
6260
6261 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006262 * Returns true if Hdmi Cec system audio mode is supported.
6263 *
6264 * @hide
6265 */
6266 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006267 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006268 public boolean isHdmiSystemAudioSupported() {
6269 try {
6270 return getService().isHdmiSystemAudioSupported();
6271 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006272 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006273 }
6274 }
6275
6276 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006277 * Return codes for listAudioPorts(), createAudioPatch() ...
6278 */
6279
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006280 /** @hide */
6281 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006282 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006283 /**
6284 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006285 */
6286 public static final int ERROR = AudioSystem.ERROR;
6287 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006288 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006289 */
6290 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6291 /** @hide
6292 */
6293 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6294 /** @hide
6295 */
6296 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6297 /** @hide
6298 */
6299 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006300 /**
6301 * An error code indicating that the object reporting it is no longer valid and needs to
6302 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006303 */
6304 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6305
6306 /**
6307 * Returns a list of descriptors for all audio ports managed by the audio framework.
6308 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6309 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6310 * See AudioPort for a list of attributes of each audio port.
6311 * @param ports An AudioPort ArrayList where the list will be returned.
6312 * @hide
6313 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006314 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006315 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006316 return updateAudioPortCache(ports, null, null);
6317 }
6318
6319 /**
6320 * Returns a list of descriptors for all audio ports managed by the audio framework as
6321 * it was before the last update calback.
6322 * @param ports An AudioPort ArrayList where the list will be returned.
6323 * @hide
6324 */
6325 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6326 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006327 }
6328
6329 /**
6330 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6331 * @see listAudioPorts(ArrayList<AudioPort>)
6332 * @hide
6333 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006334 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006335 if (devices == null) {
6336 return ERROR_BAD_VALUE;
6337 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006338 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006339 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006340 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006341 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006342 }
6343 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006344 }
6345
6346 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006347 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6348 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6349 * @hide
6350 */
6351 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6352 if (devices == null) {
6353 return ERROR_BAD_VALUE;
6354 }
6355 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6356 int status = updateAudioPortCache(null, null, ports);
6357 if (status == SUCCESS) {
6358 filterDevicePorts(ports, devices);
6359 }
6360 return status;
6361 }
6362
6363 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6364 ArrayList<AudioDevicePort> devices) {
6365 devices.clear();
6366 for (int i = 0; i < ports.size(); i++) {
6367 if (ports.get(i) instanceof AudioDevicePort) {
6368 devices.add((AudioDevicePort)ports.get(i));
6369 }
6370 }
6371 }
6372
6373 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006374 * Create a connection between two or more devices. The framework will reject the request if
6375 * device types are not compatible or the implementation does not support the requested
6376 * configuration.
6377 * NOTE: current implementation is limited to one source and one sink per patch.
6378 * @param patch AudioPatch array where the newly created patch will be returned.
6379 * As input, if patch[0] is not null, the specified patch will be replaced by the
6380 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6381 * patch and allows the implementation to optimize transitions.
6382 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6383 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6384 *
6385 * @return - {@link #SUCCESS} if connection is successful.
6386 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6387 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6388 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6389 * a patch.
6390 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6391 * - {@link #ERROR} if patch cannot be connected for any other reason.
6392 *
6393 * patch[0] contains the newly created patch
6394 * @hide
6395 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006396 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006397 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006398 AudioPortConfig[] sources,
6399 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006400 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006401 }
6402
6403 /**
6404 * Releases an existing audio patch connection.
6405 * @param patch The audio patch to disconnect.
6406 * @return - {@link #SUCCESS} if disconnection is successful.
6407 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6408 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6409 * a patch.
6410 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6411 * - {@link #ERROR} if patch cannot be released for any other reason.
6412 * @hide
6413 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006414 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006415 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006416 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006417 }
6418
6419 /**
6420 * List all existing connections between audio ports.
6421 * @param patches An AudioPatch array where the list will be returned.
6422 * @hide
6423 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006424 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006425 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006426 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006427 }
6428
6429 /**
6430 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6431 * AudioGain.buildConfig()
6432 * @hide
6433 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006434 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006435 if (port == null || gain == null) {
6436 return ERROR_BAD_VALUE;
6437 }
6438 AudioPortConfig activeConfig = port.activeConfig();
6439 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6440 activeConfig.channelMask(), activeConfig.format(), gain);
6441 config.mConfigMask = AudioPortConfig.GAIN;
6442 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006443 }
6444
6445 /**
6446 * Listener registered by client to be notified upon new audio port connections,
6447 * disconnections or attributes update.
6448 * @hide
6449 */
6450 public interface OnAudioPortUpdateListener {
6451 /**
6452 * Callback method called upon audio port list update.
6453 * @param portList the updated list of audio ports
6454 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006455 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006456
6457 /**
6458 * Callback method called upon audio patch list update.
6459 * @param patchList the updated list of audio patches
6460 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006461 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006462
6463 /**
6464 * Callback method called when the mediaserver dies
6465 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006466 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006467 }
6468
6469 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006470 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006471 * @hide
6472 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006473 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006474 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006475 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006476 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006477 }
6478
6479 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006480 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006481 * @hide
6482 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006483 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006484 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006485 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006486 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006487
6488 //
6489 // AudioPort implementation
6490 //
6491
6492 static final int AUDIOPORT_GENERATION_INIT = 0;
Eric Laurentf076db42015-01-14 13:23:27 -08006493 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT);
6494 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006495 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurentf076db42015-01-14 13:23:27 -08006496 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006497
Eric Laurentf076db42015-01-14 13:23:27 -08006498 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006499 int generation;
Eric Laurentf076db42015-01-14 13:23:27 -08006500 synchronized (sAudioPortGeneration) {
6501 generation = sAudioPortGeneration;
6502 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006503 }
6504 return generation;
6505 }
6506
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006507 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6508 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006509 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006510 synchronized (sAudioPortGeneration) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006511
Eric Laurentf076db42015-01-14 13:23:27 -08006512 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006513 int[] patchGeneration = new int[1];
6514 int[] portGeneration = new int[1];
6515 int status;
6516 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6517 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6518
6519 do {
6520 newPorts.clear();
6521 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006522 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006523 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006524 return status;
6525 }
6526 newPatches.clear();
6527 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006528 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006529 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006530 return status;
6531 }
jiabinc4ecaa52017-09-26 14:28:41 -07006532 // Loop until patch generation is the same as port generation unless audio ports
6533 // and audio patches are not null.
6534 } while (patchGeneration[0] != portGeneration[0]
6535 && (ports == null || patches == null));
6536 // If the patch generation doesn't equal port generation, return ERROR here in case
6537 // of mismatch between audio ports and audio patches.
6538 if (patchGeneration[0] != portGeneration[0]) {
6539 return ERROR;
6540 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006541
6542 for (int i = 0; i < newPatches.size(); i++) {
6543 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006544 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6545 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006546 newPatches.get(i).sources()[j] = portCfg;
6547 }
6548 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006549 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6550 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006551 newPatches.get(i).sinks()[j] = portCfg;
6552 }
6553 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006554 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6555 AudioPatch newPatch = i.next();
6556 boolean hasInvalidPort = false;
6557 for (AudioPortConfig portCfg : newPatch.sources()) {
6558 if (portCfg == null) {
6559 hasInvalidPort = true;
6560 break;
6561 }
6562 }
6563 for (AudioPortConfig portCfg : newPatch.sinks()) {
6564 if (portCfg == null) {
6565 hasInvalidPort = true;
6566 break;
6567 }
6568 }
6569 if (hasInvalidPort) {
6570 // Temporarily remove patches with invalid ports. One who created the patch
6571 // is responsible for dealing with the port change.
6572 i.remove();
6573 }
6574 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006575
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006576 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006577 sAudioPortsCached = newPorts;
6578 sAudioPatchesCached = newPatches;
6579 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006580 }
6581 if (ports != null) {
6582 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006583 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006584 }
6585 if (patches != null) {
6586 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006587 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006588 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006589 if (previousPorts != null) {
6590 previousPorts.clear();
6591 previousPorts.addAll(sPreviousAudioPortsCached);
6592 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006593 }
6594 return SUCCESS;
6595 }
6596
Eric Laurentf076db42015-01-14 13:23:27 -08006597 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006598 AudioPort port = portCfg.port();
6599 int k;
6600 for (k = 0; k < ports.size(); k++) {
6601 // compare handles because the port returned by JNI is not of the correct
6602 // subclass
6603 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006604 port = ports.get(k);
6605 break;
6606 }
6607 }
6608 if (k == ports.size()) {
6609 // this hould never happen
6610 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
6611 return null;
6612 }
6613 AudioGainConfig gainCfg = portCfg.gain();
6614 if (gainCfg != null) {
6615 AudioGain gain = port.gain(gainCfg.index());
6616 gainCfg = gain.buildConfig(gainCfg.mode(),
6617 gainCfg.channelMask(),
6618 gainCfg.values(),
6619 gainCfg.rampDurationMs());
6620 }
6621 return port.buildConfig(portCfg.samplingRate(),
6622 portCfg.channelMask(),
6623 portCfg.format(),
6624 gainCfg);
6625 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006626
6627 private OnAmPortUpdateListener mPortListener = null;
6628
6629 /**
6630 * The message sent to apps when the contents of the device list changes if they provide
Andrew Solovay5c05ded2018-10-02 14:14:42 -07006631 * a {@link Handler} object to addOnAudioDeviceConnectionListener().
Paul McLeane3383cc2015-05-08 11:41:20 -07006632 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006633 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6634 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6635 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006636
Paul McLean8e6c9f42015-05-19 11:13:41 -07006637 /**
6638 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6639 */
Jack He89f97982018-05-02 19:10:56 -07006640 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006641 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006642
6643 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006644 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6645 * the results list to only those device types they are interested in.
6646 */
6647 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07006648 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6649 * source (i.e. input) audio devices.
6650 */
6651 public static final int GET_DEVICES_INPUTS = 0x0001;
6652
6653 /**
6654 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6655 * sink (i.e. output) audio devices.
6656 */
6657 public static final int GET_DEVICES_OUTPUTS = 0x0002;
6658
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006659 /** @hide */
6660 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6661 GET_DEVICES_INPUTS,
6662 GET_DEVICES_OUTPUTS }
6663 )
6664 @Retention(RetentionPolicy.SOURCE)
6665 public @interface AudioDeviceRole {}
6666
Paul McLeane3383cc2015-05-08 11:41:20 -07006667 /**
6668 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6669 * source and sink devices.
6670 */
6671 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6672
6673 /**
6674 * Determines if a given AudioDevicePort meets the specified filter criteria.
6675 * @param port The port to test.
6676 * @param flags A set of bitflags specifying the criteria to test.
6677 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6678 **/
6679 private static boolean checkFlags(AudioDevicePort port, int flags) {
6680 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6681 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6682 }
6683
Paul McLean11354572015-08-07 12:50:48 -06006684 private static boolean checkTypes(AudioDevicePort port) {
6685 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07006686 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06006687 }
6688
Paul McLeane3383cc2015-05-08 11:41:20 -07006689 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006690 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6691 * currently connected to the system and meeting the criteria specified in the
6692 * <code>flags</code> parameter.
Paul McLeane3383cc2015-05-08 11:41:20 -07006693 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006694 * @see #GET_DEVICES_OUTPUTS
6695 * @see #GET_DEVICES_INPUTS
6696 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07006697 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6698 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006699 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006700 return getDevicesStatic(flags);
6701 }
6702
Paul McLean8e6c9f42015-05-19 11:13:41 -07006703 /**
6704 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6705 * objects from the current (internal) AudioDevicePort list.
6706 */
Paul McLean03346882015-05-12 15:36:56 -07006707 private static AudioDeviceInfo[]
6708 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006709
Paul McLean8e6c9f42015-05-19 11:13:41 -07006710 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07006711 int numRecs = 0;
6712 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006713 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006714 numRecs++;
6715 }
6716 }
6717
Paul McLean8e6c9f42015-05-19 11:13:41 -07006718 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07006719 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6720 int slot = 0;
6721 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006722 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006723 deviceList[slot++] = new AudioDeviceInfo(port);
6724 }
6725 }
6726
6727 return deviceList;
6728 }
6729
Paul McLean03346882015-05-12 15:36:56 -07006730 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07006731 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6732 * the add/remove callback mechanism to provide a list of the newly added or removed devices
6733 * rather than the whole list and make the app figure it out.
6734 * Note that calling this method with:
6735 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6736 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07006737 */
6738 private static AudioDeviceInfo[] calcListDeltas(
6739 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6740
6741 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6742
6743 AudioDevicePort cur_port = null;
6744 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6745 boolean cur_port_found = false;
6746 cur_port = ports_B.get(cur_index);
6747 for (int prev_index = 0;
6748 prev_index < ports_A.size() && !cur_port_found;
6749 prev_index++) {
6750 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6751 }
6752
6753 if (!cur_port_found) {
6754 delta_ports.add(cur_port);
6755 }
6756 }
6757
6758 return infoListFromPortList(delta_ports, flags);
6759 }
6760
Paul McLeane3383cc2015-05-08 11:41:20 -07006761 /**
Paul McLean03346882015-05-12 15:36:56 -07006762 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6763 * connected to the system and meeting the criteria specified in the <code>flags</code>
6764 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006765 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07006766 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006767 * @see #GET_DEVICES_OUTPUTS
6768 * @see #GET_DEVICES_INPUTS
6769 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07006770 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6771 * @hide
6772 */
6773 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6774 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6775 int status = AudioManager.listAudioDevicePorts(ports);
6776 if (status != AudioManager.SUCCESS) {
6777 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07006778 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07006779 }
6780
6781 return infoListFromPortList(ports, flags);
6782 }
6783
6784 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07006785 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6786 * @param portId The audio port ID to look up for.
6787 * @param flags A set of bitflags specifying the criteria to test.
6788 * @see #GET_DEVICES_OUTPUTS
6789 * @see #GET_DEVICES_INPUTS
6790 * @see #GET_DEVICES_ALL
6791 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6792 * @hide
6793 */
6794 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6795 if (portId == 0) {
6796 return null;
6797 }
6798 AudioDeviceInfo[] devices = getDevicesStatic(flags);
6799 for (AudioDeviceInfo device : devices) {
6800 if (device.getId() == portId) {
6801 return device;
6802 }
6803 }
6804 return null;
6805 }
6806
6807 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006808 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07006809 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006810 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6811 * notifications.
6812 * @param handler Specifies the {@link Handler} object for the thread on which to execute
6813 * the callback. If <code>null</code>, the {@link Handler} associated with the main
6814 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07006815 */
Paul McLean03346882015-05-12 15:36:56 -07006816 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08006817 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07006818 synchronized (mDeviceCallbacks) {
6819 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006820 if (mDeviceCallbacks.size() == 0) {
6821 if (mPortListener == null) {
6822 mPortListener = new OnAmPortUpdateListener();
6823 }
6824 registerAudioPortUpdateListener(mPortListener);
6825 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006826 NativeEventHandlerDelegate delegate =
6827 new NativeEventHandlerDelegate(callback, handler);
6828 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07006829 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07006830 }
6831 }
6832 }
6833
6834 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006835 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07006836 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006837 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08006838 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07006839 */
Paul McLean03346882015-05-12 15:36:56 -07006840 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6841 synchronized (mDeviceCallbacks) {
6842 if (mDeviceCallbacks.containsKey(callback)) {
6843 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07006844 if (mDeviceCallbacks.size() == 0) {
6845 unregisterAudioPortUpdateListener(mPortListener);
6846 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006847 }
6848 }
6849 }
6850
jiabinc0f49442018-01-05 10:23:50 -08006851 /**
6852 * Set port id for microphones by matching device type and address.
6853 * @hide
6854 */
6855 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6856 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6857 for (int i = microphones.size() - 1; i >= 0; i--) {
6858 boolean foundPortId = false;
6859 for (AudioDeviceInfo device : devices) {
6860 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6861 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6862 microphones.get(i).setId(device.getId());
6863 foundPortId = true;
6864 break;
6865 }
6866 }
6867 if (!foundPortId) {
6868 Log.i(TAG, "Failed to find port id for device with type:"
6869 + microphones.get(i).getType() + " address:"
6870 + microphones.get(i).getAddress());
6871 microphones.remove(i);
6872 }
6873 }
6874 }
6875
6876 /**
jiabin589a2362018-02-22 16:21:53 -08006877 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6878 * @hide
6879 */
6880 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6881 int deviceType = deviceInfo.getType();
6882 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6883 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6884 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6885 : MicrophoneInfo.LOCATION_PERIPHERAL;
6886 MicrophoneInfo microphone = new MicrophoneInfo(
6887 deviceInfo.getPort().name() + deviceInfo.getId(),
6888 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6889 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6890 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6891 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6892 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6893 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6894 microphone.setId(deviceInfo.getId());
6895 return microphone;
6896 }
6897
6898 /**
jiabind0be5b22018-04-10 14:10:04 -07006899 * Add {@link MicrophoneInfo} by device information while filtering certain types.
6900 */
6901 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6902 HashSet<Integer> filterTypes) {
6903 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6904 for (AudioDeviceInfo device : devices) {
6905 if (filterTypes.contains(device.getType())) {
6906 continue;
6907 }
6908 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6909 microphones.add(microphone);
6910 }
6911 }
6912
6913 /**
jiabinc0f49442018-01-05 10:23:50 -08006914 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6915 * of all available microphones. The list is empty when no microphones are available
6916 * on the device. An error during the query will result in an IOException being thrown.
6917 *
6918 * @return a list that contains all microphones' characteristics
6919 * @throws IOException if an error occurs.
6920 */
6921 public List<MicrophoneInfo> getMicrophones() throws IOException {
6922 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6923 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006924 HashSet<Integer> filterTypes = new HashSet<>();
6925 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08006926 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07006927 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07006928 if (status != AudioManager.ERROR_INVALID_OPERATION) {
6929 Log.e(TAG, "getMicrophones failed:" + status);
6930 }
6931 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07006932 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6933 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08006934 }
6935 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006936 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6937 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08006938 return microphones;
6939 }
6940
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006941 /**
6942 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01006943 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006944 *
6945 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01006946 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006947 * @hide
6948 */
William Escandea05cb452021-12-08 14:14:19 +01006949 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6950 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
6951 ArrayList<Integer> formatsList = new ArrayList<>();
6952 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006953
William Escandea05cb452021-12-08 14:14:19 +01006954 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
6955 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006956 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01006957 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
6958 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006959 }
6960
William Escandea05cb452021-12-08 14:14:19 +01006961 for (Integer format : formatsList) {
6962 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6963 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
Etienne Ruffieux2c5180a2022-03-08 13:31:41 +00006964 codecConfigList.add(
6965 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006966 }
William Escandea05cb452021-12-08 14:14:19 +01006967 }
6968 return codecConfigList;
6969 }
6970
6971 /**
6972 * Returns a list of audio formats that corresponds to encoding formats
6973 * supported on offload path for Le audio playback.
6974 *
6975 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
6976 * supported for offload Le Audio playback
6977 * @hide
6978 */
6979 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6980 @NonNull
6981 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
6982 ArrayList<Integer> formatsList = new ArrayList<>();
6983 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
6984
6985 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
6986 AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
6987 if (status != AudioManager.SUCCESS) {
6988 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08006989 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006990 }
William Escandea05cb452021-12-08 14:14:19 +01006991
6992 for (Integer format : formatsList) {
6993 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
6994 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6995 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
6996 .setCodecType(btLeAudioCodec)
6997 .build());
6998 }
6999 }
7000 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08007001 }
7002
Paul McLeancbeb8a22015-06-10 08:21:27 -07007003 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
7004 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
7005 // of the ports that exist at the time of the last notification.
7006 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
7007
Paul McLeane3383cc2015-05-08 11:41:20 -07007008 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007009 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07007010 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07007011 */
jiabin8c3a7672018-05-22 15:44:21 -07007012 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07007013 int status;
7014
Paul McLeancbeb8a22015-06-10 08:21:27 -07007015 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07007016 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
7017 status = AudioManager.listAudioDevicePorts(current_ports);
7018 if (status != AudioManager.SUCCESS) {
7019 return;
7020 }
7021
Paul McLeancbeb8a22015-06-10 08:21:27 -07007022 if (handler != null) {
7023 // This is the callback for the registration, so send the current list
7024 AudioDeviceInfo[] deviceList =
7025 infoListFromPortList(current_ports, GET_DEVICES_ALL);
7026 handler.sendMessage(
7027 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
7028 } else {
7029 AudioDeviceInfo[] added_devices =
7030 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
7031 AudioDeviceInfo[] removed_devices =
7032 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07007033 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07007034 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
7035 handler = mDeviceCallbacks.valueAt(i).getHandler();
7036 if (handler != null) {
7037 if (removed_devices.length != 0) {
7038 handler.sendMessage(Message.obtain(handler,
7039 MSG_DEVICES_DEVICES_REMOVED,
7040 removed_devices));
7041 }
7042 if (added_devices.length != 0) {
7043 handler.sendMessage(Message.obtain(handler,
7044 MSG_DEVICES_DEVICES_ADDED,
7045 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07007046 }
Paul McLean03346882015-05-12 15:36:56 -07007047 }
7048 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007049 }
7050 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007051
7052 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07007053 }
7054
7055 /**
7056 * Handles Port list update notifications from the AudioManager
7057 */
7058 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
7059 static final String TAG = "OnAmPortUpdateListener";
7060 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07007061 synchronized (mDeviceCallbacks) {
7062 broadcastDeviceListChange_sync(null);
7063 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007064 }
7065
7066 /**
7067 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007068 * Note: We don't do anything with Patches at this time, so ignore this notification.
7069 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07007070 */
7071 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
7072
7073 /**
7074 * Callback method called when the mediaserver dies
7075 */
7076 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07007077 synchronized (mDeviceCallbacks) {
7078 broadcastDeviceListChange_sync(null);
7079 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007080 }
7081 }
7082
Eric Laurent1d3cdce2018-01-20 10:31:21 -08007083
7084 /**
7085 * @hide
7086 * Abstract class to receive event notification about audioserver process state.
7087 */
7088 @SystemApi
7089 public abstract static class AudioServerStateCallback {
7090 public void onAudioServerDown() { }
7091 public void onAudioServerUp() { }
7092 }
7093
7094 private Executor mAudioServerStateExec;
7095 private AudioServerStateCallback mAudioServerStateCb;
7096 private final Object mAudioServerStateCbLock = new Object();
7097
7098 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
7099 new IAudioServerStateDispatcher.Stub() {
7100 @Override
7101 public void dispatchAudioServerStateChange(boolean state) {
7102 Executor exec;
7103 AudioServerStateCallback cb;
7104
7105 synchronized (mAudioServerStateCbLock) {
7106 exec = mAudioServerStateExec;
7107 cb = mAudioServerStateCb;
7108 }
7109
7110 if ((exec == null) || (cb == null)) {
7111 return;
7112 }
7113 if (state) {
7114 exec.execute(() -> cb.onAudioServerUp());
7115 } else {
7116 exec.execute(() -> cb.onAudioServerDown());
7117 }
7118 }
7119 };
7120
7121 /**
7122 * @hide
7123 * Registers a callback for notification of audio server state changes.
7124 * @param executor {@link Executor} to handle the callbacks
7125 * @param stateCallback the callback to receive the audio server state changes
7126 * To remove the callabck, pass a null reference for both executor and stateCallback.
7127 */
7128 @SystemApi
7129 public void setAudioServerStateCallback(@NonNull Executor executor,
7130 @NonNull AudioServerStateCallback stateCallback) {
7131 if (stateCallback == null) {
7132 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
7133 }
7134 if (executor == null) {
7135 throw new IllegalArgumentException(
7136 "Illegal null Executor for the AudioServerStateCallback");
7137 }
7138
7139 synchronized (mAudioServerStateCbLock) {
7140 if (mAudioServerStateCb != null) {
7141 throw new IllegalStateException(
7142 "setAudioServerStateCallback called with already registered callabck");
7143 }
7144 final IAudioService service = getService();
7145 try {
7146 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7147 } catch (RemoteException e) {
7148 throw e.rethrowFromSystemServer();
7149 }
7150 mAudioServerStateExec = executor;
7151 mAudioServerStateCb = stateCallback;
7152 }
7153 }
7154
7155 /**
7156 * @hide
7157 * Unregisters the callback for notification of audio server state changes.
7158 */
7159 @SystemApi
7160 public void clearAudioServerStateCallback() {
7161 synchronized (mAudioServerStateCbLock) {
7162 if (mAudioServerStateCb != null) {
7163 final IAudioService service = getService();
7164 try {
7165 service.unregisterAudioServerStateDispatcher(
7166 mAudioServerStateDispatcher);
7167 } catch (RemoteException e) {
7168 throw e.rethrowFromSystemServer();
7169 }
7170 }
7171 mAudioServerStateExec = null;
7172 mAudioServerStateCb = null;
7173 }
7174 }
7175
7176 /**
7177 * @hide
7178 * Checks if native audioservice is running or not.
7179 * @return true if native audioservice runs, false otherwise.
7180 */
7181 @SystemApi
7182 public boolean isAudioServerRunning() {
7183 final IAudioService service = getService();
7184 try {
7185 return service.isAudioServerRunning();
7186 } catch (RemoteException e) {
7187 throw e.rethrowFromSystemServer();
7188 }
7189 }
7190
jiabin39940752018-04-02 18:18:45 -07007191 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007192 * Sets the surround sound mode.
7193 *
7194 * @return true if successful, otherwise false
7195 */
7196 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
7197 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7198 try {
7199 return getService().setEncodedSurroundMode(mode);
7200 } catch (RemoteException e) {
7201 throw e.rethrowFromSystemServer();
7202 }
7203 }
7204
7205 /**
7206 * Gets the surround sound mode.
7207 *
7208 * @return true if successful, otherwise false
7209 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007210 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7211 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007212 return getService().getEncodedSurroundMode(
7213 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007214 } catch (RemoteException e) {
7215 throw e.rethrowFromSystemServer();
7216 }
7217 }
7218
7219 /**
jiabin39940752018-04-02 18:18:45 -07007220 * @hide
7221 * Returns all surround formats.
7222 * @return a map where the key is a surround format and
7223 * the value indicates the surround format is enabled or not
7224 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007225 @TestApi
7226 @NonNull
jiabin39940752018-04-02 18:18:45 -07007227 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007228 try {
7229 return getService().getSurroundFormats();
7230 } catch (RemoteException e) {
7231 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007232 }
jiabin39940752018-04-02 18:18:45 -07007233 }
7234
7235 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007236 * Sets and persists a certain surround format as enabled or not.
7237 * <p>
7238 * This API is called by TvSettings surround sound menu when user enables or disables a
7239 * surround sound format. This setting is persisted as global user setting.
7240 * Applications should revert their changes to surround sound settings unless they intend to
7241 * modify the global user settings across all apps. The framework does not auto-revert an
7242 * application's settings after a lifecycle event. Audio focus is not required to apply these
7243 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007244 *
jiabin39940752018-04-02 18:18:45 -07007245 * @param enabled the required surround format state, true for enabled, false for disabled
7246 * @return true if successful, otherwise false
7247 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007248 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007249 public boolean setSurroundFormatEnabled(
7250 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007251 try {
7252 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7253 } catch (RemoteException e) {
7254 throw e.rethrowFromSystemServer();
7255 }
7256 }
7257
7258 /**
7259 * Gets whether a certain surround format is enabled or not.
7260 * @param audioFormat a surround format
7261 *
7262 * @return whether the required surround format is enabled
7263 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007264 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7265 try {
7266 return getService().isSurroundFormatEnabled(audioFormat);
7267 } catch (RemoteException e) {
7268 throw e.rethrowFromSystemServer();
7269 }
jiabin39940752018-04-02 18:18:45 -07007270 }
7271
7272 /**
7273 * @hide
7274 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007275 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007276 *
Kriti Dang01924232021-03-02 13:51:09 +01007277 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007278 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007279 @TestApi
7280 @NonNull
7281 public List<Integer> getReportedSurroundFormats() {
7282 try {
7283 return getService().getReportedSurroundFormats();
7284 } catch (RemoteException e) {
7285 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007286 }
jiabin39940752018-04-02 18:18:45 -07007287 }
7288
jiabin66f9e722018-11-02 16:20:19 -07007289 /**
7290 * Return if audio haptic coupled playback is supported or not.
7291 *
7292 * @return whether audio haptic playback supported.
7293 */
7294 public static boolean isHapticPlaybackSupported() {
7295 return AudioSystem.isHapticPlaybackSupported();
7296 }
7297
François Gaffie0699fec2018-07-09 14:35:10 +02007298 /**
7299 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08007300 * Indicates whether a platform supports the Ultrasound feature which covers the playback
7301 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
7302 * usage will be
7303 * To start the Ultrasound playback:
7304 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
7305 * To start the Ultrasound capture:
7306 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
7307 *
7308 * @return whether the ultrasound feature is supported, true when platform supports both
7309 * Ultrasound playback and capture, false otherwise.
7310 */
7311 @SystemApi
Carter Hsu3ea30de42022-02-15 15:59:00 +08007312 @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
7313 public boolean isUltrasoundSupported() {
7314 try {
7315 return getService().isUltrasoundSupported();
7316 } catch (RemoteException e) {
7317 throw e.rethrowFromSystemServer();
7318 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08007319 }
7320
7321 /**
7322 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02007323 * Introspection API to retrieve audio product strategies.
7324 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7325 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7326 * by OEM without any needs of AOSP patches.
7327 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7328 * strategy refered either by its index or human readable string. It will allow clients
7329 * application to start streaming data using these {@link AudioAttributes} on the selected
7330 * device by Audio Policy Engine.
7331 * @return a (possibly zero-length) array of
7332 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7333 */
7334 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007335 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007336 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007337 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007338 final IAudioService service = getService();
7339 try {
7340 return service.getAudioProductStrategies();
7341 } catch (RemoteException e) {
7342 throw e.rethrowFromSystemServer();
7343 }
7344 }
7345
François Gaffieadcd00a2018-09-18 17:06:26 +02007346 /**
7347 * @hide
7348 * Introspection API to retrieve audio volume groups.
7349 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7350 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007351 * @return a (possibly zero-length) List of
7352 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007353 */
7354 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007355 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007356 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007357 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007358 final IAudioService service = getService();
7359 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007360 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007361 } catch (RemoteException e) {
7362 throw e.rethrowFromSystemServer();
7363 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007364 }
7365
7366 /**
7367 * @hide
7368 * Callback registered by client to be notified upon volume group change.
7369 */
7370 @SystemApi
7371 public abstract static class VolumeGroupCallback {
7372 /**
7373 * Callback method called upon audio volume group change.
7374 * @param group the group for which the volume has changed
7375 */
7376 public void onAudioVolumeGroupChanged(int group, int flags) {}
7377 }
7378
7379 /**
7380 * @hide
7381 * Register an audio volume group change listener.
7382 * @param callback the {@link VolumeGroupCallback} to register
7383 */
7384 @SystemApi
7385 public void registerVolumeGroupCallback(
7386 @NonNull Executor executor,
7387 @NonNull VolumeGroupCallback callback) {
7388 Preconditions.checkNotNull(executor, "executor must not be null");
7389 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7390 sAudioAudioVolumeGroupChangedHandler.init();
7391 // TODO: make use of executor
7392 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7393 }
7394
7395 /**
7396 * @hide
7397 * Unregister an audio volume group change listener.
7398 * @param callback the {@link VolumeGroupCallback} to unregister
7399 */
7400 @SystemApi
7401 public void unregisterVolumeGroupCallback(
7402 @NonNull VolumeGroupCallback callback) {
7403 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7404 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7405 }
jiabin39940752018-04-02 18:18:45 -07007406
jiabinad225202019-03-20 15:22:50 -07007407 /**
7408 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007409 *
7410 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007411 * @param uri the {@link Uri} of the asset.
7412 * @return true if the assert contains haptic channels.
7413 * @hide
7414 */
jiabincfcf1032021-07-01 16:30:50 -07007415 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7416 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007417 try {
jiabincfcf1032021-07-01 16:30:50 -07007418 extractor.setDataSource(context, uri, null);
7419 for (int i = 0; i < extractor.getTrackCount(); i++) {
7420 MediaFormat format = extractor.getTrackFormat(i);
7421 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7422 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7423 return true;
7424 }
7425 }
7426 } catch (IOException e) {
7427 Log.e(TAG, "hasHapticChannels failure:" + e);
7428 }
7429 return false;
7430 }
7431
7432 /**
7433 * Return if an asset contains haptic channels or not.
7434 *
7435 * @param context the {@link Context} to resolve the uri.
7436 * @param uri the {@link Uri} of the asset.
7437 * @return true if the assert contains haptic channels.
7438 * @hide
7439 */
7440 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7441 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07007442
jiabincfcf1032021-07-01 16:30:50 -07007443 if (context != null) {
7444 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07007445 }
7446
7447 Context cachedContext = sContext.get();
7448 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07007449 if (DEBUG) {
7450 Log.d(TAG, "Try to use static context to query if having haptic channels");
7451 }
jiabin0f3339c2021-07-09 11:50:07 -07007452 return hasHapticChannelsImpl(cachedContext, uri);
7453 }
7454
7455 // Try with audio service context, this may fail to get correct result.
7456 if (DEBUG) {
7457 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7458 }
7459 try {
7460 return getService().hasHapticChannels(uri);
7461 } catch (RemoteException e) {
7462 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07007463 }
7464 }
7465
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007466 /**
7467 * Set whether or not there is an active RTT call.
7468 * This method should be called by Telecom service.
7469 * @hide
7470 * TODO: make this a @SystemApi
7471 */
7472 public static void setRttEnabled(boolean rttEnabled) {
7473 try {
7474 getService().setRttEnabled(rttEnabled);
7475 } catch (RemoteException e) {
7476 throw e.rethrowFromSystemServer();
7477 }
7478 }
7479
Jin Seok Park16aeba382020-08-06 12:52:54 +09007480 /**
7481 * Adjusts the volume of the most relevant stream, or the given fallback
7482 * stream.
7483 * <p>
7484 * This method should only be used by applications that replace the
7485 * platform-wide management of audio settings or the main telephony
7486 * application.
7487 * <p>
7488 * This method has no effect if the device implements a fixed volume policy
7489 * as indicated by {@link #isVolumeFixed()}.
7490 * <p>This API checks if the caller has the necessary permissions based on the provided
7491 * component name, uid, and pid values.
7492 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7493 *
7494 * @param suggestedStreamType The stream type that will be used if there
7495 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7496 * valid here.
7497 * @param direction The direction to adjust the volume. One of
7498 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7499 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7500 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7501 * @param flags One or more flags.
7502 * @param packageName the package name of client application
7503 * @param uid the uid of client application
7504 * @param pid the pid of client application
7505 * @param targetSdkVersion the target sdk version of client application
7506 * @see #adjustVolume(int, int)
7507 * @see #adjustStreamVolume(int, int, int)
7508 * @see #setStreamVolume(int, int, int)
7509 * @see #isVolumeFixed()
7510 *
7511 * @hide
7512 */
7513 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7514 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7515 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7516 try {
7517 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7518 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7519 } catch (RemoteException e) {
7520 throw e.rethrowFromSystemServer();
7521 }
7522 }
7523
7524 /**
7525 * Adjusts the volume of a particular stream by one step in a direction.
7526 * <p>
7527 * This method should only be used by applications that replace the platform-wide
7528 * management of audio settings or the main telephony application.
7529 * <p>This method has no effect if the device implements a fixed volume policy
7530 * as indicated by {@link #isVolumeFixed()}.
7531 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7532 * unless the app has been granted Do Not Disturb Access.
7533 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7534 * <p>This API checks if the caller has the necessary permissions based on the provided
7535 * component name, uid, and pid values.
7536 * See {@link #adjustStreamVolume(int, int, int)}.
7537 *
7538 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7539 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7540 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7541 * @param direction The direction to adjust the volume. One of
7542 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7543 * {@link #ADJUST_SAME}.
7544 * @param flags One or more flags.
7545 * @param packageName the package name of client application
7546 * @param uid the uid of client application
7547 * @param pid the pid of client application
7548 * @param targetSdkVersion the target sdk version of client application
7549 * @see #adjustVolume(int, int)
7550 * @see #setStreamVolume(int, int, int)
7551 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7552 * and the caller is not granted notification policy access.
7553 *
7554 * @hide
7555 */
7556 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7557 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7558 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7559 try {
7560 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7561 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7562 } catch (RemoteException e) {
7563 throw e.rethrowFromSystemServer();
7564 }
7565 }
7566
7567 /**
7568 * Sets the volume index for a particular stream.
7569 * <p>This method has no effect if the device implements a fixed volume policy
7570 * as indicated by {@link #isVolumeFixed()}.
7571 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7572 * the app has been granted Do Not Disturb Access.
7573 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7574 * <p>This API checks if the caller has the necessary permissions based on the provided
7575 * component name, uid, and pid values.
7576 * See {@link #setStreamVolume(int, int, int)}.
7577 *
7578 * @param streamType The stream whose volume index should be set.
7579 * @param index The volume index to set. See
7580 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7581 * @param flags One or more flags.
7582 * @param packageName the package name of client application
7583 * @param uid the uid of client application
7584 * @param pid the pid of client application
7585 * @param targetSdkVersion the target sdk version of client application
7586 * @see #getStreamMaxVolume(int)
7587 * @see #getStreamVolume(int)
7588 * @see #isVolumeFixed()
7589 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7590 * and the caller is not granted notification policy access.
7591 *
7592 * @hide
7593 */
7594 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7595 public void setStreamVolumeForUid(int streamType, int index, int flags,
7596 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7597 try {
7598 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7599 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7600 } catch (RemoteException e) {
7601 throw e.rethrowFromSystemServer();
7602 }
7603 }
7604
7605
hjin81.lee4e984e52019-12-05 14:34:52 +09007606 /** @hide
7607 * TODO: make this a @SystemApi */
7608 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7609 public void setMultiAudioFocusEnabled(boolean enabled) {
7610 try {
7611 getService().setMultiAudioFocusEnabled(enabled);
7612 } catch (RemoteException e) {
7613 throw e.rethrowFromSystemServer();
7614 }
7615 }
7616
Eric Laurent43a78de2020-07-24 17:11:15 -07007617
7618 /**
7619 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7620 * For more details on Hardware A/V synchronization please refer to
7621 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7622 * media tunneling documentation</a>.
7623 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7624 * @return the HW A/V sync ID for this audio session (an integer different from 0).
7625 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7626 */
7627 public int getAudioHwSyncForSession(int sessionId) {
7628 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7629 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7630 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7631 }
7632 return hwSyncId;
7633 }
7634
Eric Laurentb36d4a12020-10-09 09:52:49 -07007635 /**
7636 * Selects the audio device that should be used for communication use cases, for instance voice
7637 * or video calls. This method can be used by voice or video chat applications to select a
7638 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01007639 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7640 * {@link #getAvailableCommunicationDevices()}.
7641 * The selection is active as long as the requesting application process lives, until
7642 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007643 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01007644 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007645 * <p>In case of simultaneous requests by multiple applications the priority is given to the
7646 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7647 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7648 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7649 * telephony application with permission
7650 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7651 * <p> If the requested devices is not currently available, the request will be rejected and
7652 * the method will return false.
7653 * <p>This API replaces the following deprecated APIs:
7654 * <ul>
7655 * <li> {@link #startBluetoothSco()}
7656 * <li> {@link #stopBluetoothSco()}
7657 * <li> {@link #setSpeakerphoneOn(boolean)}
7658 * </ul>
7659 * <h4>Example</h4>
7660 * <p>The example below shows how to enable and disable speakerphone mode.
7661 * <pre class="prettyprint">
7662 * // Get an AudioManager instance
7663 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01007664 * AudioDeviceInfo speakerDevice = null;
7665 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7666 * for (AudioDeviceInfo device : devices) {
7667 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7668 * speakerDevice = device;
7669 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007670 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007671 * }
7672 * if (speakerDevice != null) {
7673 * // Turn speakerphone ON.
7674 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
7675 * if (!result) {
7676 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007677 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007678 * // Turn speakerphone OFF.
7679 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007680 * }
7681 * </pre>
7682 * @param device the requested audio device.
7683 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7684 * @throws IllegalArgumentException If an invalid device is specified.
7685 */
Eric Laurent7412f572021-02-11 15:10:31 +01007686 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007687 Objects.requireNonNull(device);
7688 try {
7689 if (device.getId() == 0) {
Eric Laurentc18e5a12023-01-20 19:30:09 +01007690 Log.w(TAG, "setCommunicationDevice: device not found: " + device);
7691 return false;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007692 }
Eric Laurent7412f572021-02-11 15:10:31 +01007693 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007694 } catch (RemoteException e) {
7695 throw e.rethrowFromSystemServer();
7696 }
7697 }
7698
7699 /**
7700 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01007701 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007702 */
Eric Laurent7412f572021-02-11 15:10:31 +01007703 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007704 try {
Eric Laurent7412f572021-02-11 15:10:31 +01007705 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007706 } catch (RemoteException e) {
7707 throw e.rethrowFromSystemServer();
7708 }
7709 }
7710
7711 /**
7712 * Returns currently selected audio device for communication.
7713 * <p>This API replaces the following deprecated APIs:
7714 * <ul>
7715 * <li> {@link #isBluetoothScoOn()}
7716 * <li> {@link #isSpeakerphoneOn()}
7717 * </ul>
7718 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01007719 * currently selected for communication use cases. Can be null on platforms
7720 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007721 * is used.
7722 */
7723 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01007724 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007725 try {
7726 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01007727 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7728 } catch (RemoteException e) {
7729 throw e.rethrowFromSystemServer();
7730 }
7731 }
7732
7733 /**
7734 * Returns a list of audio devices that can be selected for communication use cases via
7735 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7736 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7737 */
7738 @NonNull
7739 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7740 try {
7741 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7742 int[] portIds = getService().getAvailableCommunicationDeviceIds();
7743 for (int portId : portIds) {
7744 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7745 if (device == null) {
7746 continue;
7747 }
7748 devices.add(device);
7749 }
7750 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007751 } catch (RemoteException e) {
7752 throw e.rethrowFromSystemServer();
7753 }
7754 }
7755
7756 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01007757 * Returns a list of direct {@link AudioProfile} that are supported for the specified
7758 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
7759 * is possible.
7760 *
7761 * <p>Direct playback means that the audio stream is not resampled or downmixed
7762 * by the framework. Checking for direct support can help the app select the representation
7763 * of audio content that most closely matches the capabilities of the device and peripherals
7764 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
7765 * or mixed with other streams, if needed.
7766 * <p>When using this information to inform your application which audio format to play,
7767 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
7768 * @param attributes a non-null {@link AudioAttributes} instance.
7769 * @return a list of {@link AudioProfile}
7770 */
7771 @NonNull
7772 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
7773 Objects.requireNonNull(attributes);
7774 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
7775 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
7776 if (status != SUCCESS) {
7777 Log.w(TAG, "getDirectProfilesForAttributes failed.");
7778 return new ArrayList<>();
7779 }
7780 return audioProfilesList;
7781 }
7782
7783 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007784 * @hide
7785 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7786 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7787 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7788 * The method will return null if no device of the provided type is connected.
7789 * If more than one device of the provided type is connected, an object corresponding to the
7790 * first device encountered in the enumeration list will be returned.
7791 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01007792 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007793 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7794 * @throws IllegalArgumentException If an invalid device type is specified.
7795 */
7796 @TestApi
7797 @Nullable
7798 public static AudioDeviceInfo getDeviceInfoFromType(
7799 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01007800 return getDeviceInfoFromTypeAndAddress(deviceType, null);
7801 }
7802
Eric Laurent78eef3a2021-11-09 16:10:42 +01007803 /**
Eric Laurent7412f572021-02-11 15:10:31 +01007804 * @hide
7805 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7806 * address provided.
7807 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7808 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7809 * If a null address is provided, the matching will happen on the type only.
7810 * The method will return null if no device of the provided type and address is connected.
7811 * If more than one device of the provided type is connected, an object corresponding to the
7812 * first device encountered in the enumeration list will be returned.
7813 * @param type The device device for which an <code>AudioDeviceInfo</code>
7814 * object is queried.
7815 * @param address The device address for which an <code>AudioDeviceInfo</code>
7816 * object is queried or null if requesting match on type only.
7817 * @return An AudioDeviceInfo object or null if no matching device is connected.
7818 * @throws IllegalArgumentException If an invalid device type is specified.
7819 */
7820 @Nullable
7821 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7822 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007823 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01007824 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007825 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01007826 if (device.getType() == type) {
7827 deviceForType = device;
7828 if (address == null || address.equals(device.getAddress())) {
7829 return device;
7830 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007831 }
7832 }
Eric Laurent7412f572021-02-11 15:10:31 +01007833 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007834 }
7835
7836 /**
7837 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007838 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007839 */
7840 public interface OnCommunicationDeviceChangedListener {
7841 /**
7842 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007843 * @param device the audio device requested for communication use cases.
7844 * Can be null on platforms not supporting
7845 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007846 */
7847 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7848 }
7849
7850 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007851 * manages the OnCommunicationDeviceChangedListener listeners and the
7852 * CommunicationDeviceDispatcherStub
7853 */
7854 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
7855 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
7856 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007857 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007858 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007859 * @param executor
7860 * @param listener
7861 */
7862 public void addOnCommunicationDeviceChangedListener(
7863 @NonNull @CallbackExecutor Executor executor,
7864 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007865 mCommDeviceChangedListenerMgr.addListener(
7866 executor, listener, "addOnCommunicationDeviceChangedListener",
7867 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007868 }
7869
7870 /**
7871 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007872 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007873 * @param listener
7874 */
7875 public void removeOnCommunicationDeviceChangedListener(
7876 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007877 mCommDeviceChangedListenerMgr.removeListener(listener,
7878 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07007879 }
7880
Eric Laurentb36d4a12020-10-09 09:52:49 -07007881 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007882 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007883
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007884 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007885 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007886 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007887 if (register) {
7888 getService().registerCommunicationDeviceDispatcher(this);
7889 } else {
7890 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007891 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007892 } catch (RemoteException e) {
7893 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007894 }
7895 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007896
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007897 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007898 public void dispatchCommunicationDeviceChanged(int portId) {
7899 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007900 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007901 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07007902 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007903 }
7904
Eric Laurent78eef3a2021-11-09 16:10:42 +01007905
7906 /**
7907 * @hide
7908 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
7909 * PSTN call.
7910 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
7911 * an AudioTrack for call uplink audio injection and
7912 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
7913 * an AudioRecord for call downlink audio extraction.
7914 * @return true if PSTN call audio is accessible, false otherwise.
7915 */
7916 @TestApi
7917 @SystemApi
7918 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
7919 public boolean isPstnCallAudioInterceptable() {
7920 final IAudioService service = getService();
7921 try {
7922 return service.isPstnCallAudioInterceptable();
7923 } catch (RemoteException e) {
7924 throw e.rethrowFromSystemServer();
7925 }
7926 }
7927
7928 /** @hide */
7929 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
7930 CALL_REDIRECT_NONE,
7931 CALL_REDIRECT_PSTN,
7932 CALL_REDIRECT_VOIP }
7933 )
7934 @Retention(RetentionPolicy.SOURCE)
7935 public @interface CallRedirectionMode {}
7936
7937 /**
7938 * Not used for call redirection
7939 * @hide
7940 */
7941 public static final int CALL_REDIRECT_NONE = 0;
7942 /**
7943 * Used to redirect PSTN call
7944 * @hide
7945 */
7946 public static final int CALL_REDIRECT_PSTN = 1;
7947 /**
7948 * Used to redirect VoIP call
7949 * @hide
7950 */
7951 public static final int CALL_REDIRECT_VOIP = 2;
7952
7953
7954 private @CallRedirectionMode int getCallRedirectMode() {
7955 int mode = getMode();
7956 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
7957 || mode == MODE_CALL_REDIRECT) {
7958 return CALL_REDIRECT_PSTN;
7959 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
7960 return CALL_REDIRECT_VOIP;
7961 }
7962 return CALL_REDIRECT_NONE;
7963 }
7964
7965 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
7966 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
7967 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
7968 throw new UnsupportedOperationException(" Unsupported encoding ");
7969 }
7970 if (format.getSampleRate() < 8000
7971 || format.getSampleRate() > 48000) {
7972 throw new UnsupportedOperationException(" Unsupported sample rate ");
7973 }
7974 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
7975 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
7976 throw new UnsupportedOperationException(" Unsupported output channel mask ");
7977 }
7978 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
7979 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
7980 throw new UnsupportedOperationException(" Unsupported input channel mask ");
7981 }
7982 }
7983
7984 class CallIRedirectionClientInfo {
7985 public WeakReference trackOrRecord;
7986 public int redirectMode;
7987 }
7988
7989 private Object mCallRedirectionLock = new Object();
7990 @GuardedBy("mCallRedirectionLock")
7991 private CallInjectionModeChangedListener mCallRedirectionModeListener;
7992 @GuardedBy("mCallRedirectionLock")
7993 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
7994
7995 /**
7996 * @hide
7997 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
7998 * This can be used for functions like call screening or call audio redirection and is reserved
7999 * to system apps with privileged permission.
8000 * @param format the desired audio format for audio playback.
8001 * p>Formats accepted are:
8002 * <ul>
8003 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8004 * <li><em>Channel mask</em> - Mono or Stereo </li>
8005 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8006 * </ul>
8007 *
8008 * @return The AudioTrack used for audio injection
8009 * @throws NullPointerException if AudioFormat argument is null.
8010 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8011 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8012 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8013 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8014 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8015 * or MODE_COMMUNICATION_REDIRECT.
8016 */
8017 @TestApi
8018 @SystemApi
8019 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8020 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
8021 Objects.requireNonNull(format);
8022 checkCallRedirectionFormat(format, true /* isOutput */);
8023
8024 AudioTrack track = null;
8025 int redirectMode = getCallRedirectMode();
8026 if (redirectMode == CALL_REDIRECT_NONE) {
8027 throw new IllegalStateException(
8028 " not available in mode " + AudioSystem.modeToString(getMode()));
8029 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8030 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8031 }
8032
8033 track = new AudioTrack.Builder()
8034 .setAudioAttributes(new AudioAttributes.Builder()
8035 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
8036 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
8037 .build())
8038 .setAudioFormat(format)
8039 .setCallRedirectionMode(redirectMode)
8040 .build();
8041
8042 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
8043 synchronized (mCallRedirectionLock) {
8044 if (mCallRedirectionModeListener == null) {
8045 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8046 try {
8047 addOnModeChangedListener(
8048 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8049 } catch (Exception e) {
8050 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8051 mCallRedirectionModeListener = null;
8052 throw new UnsupportedOperationException(" Cannot register mode listener ");
8053 }
8054 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8055 }
8056 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8057 info.redirectMode = redirectMode;
8058 info.trackOrRecord = new WeakReference<AudioTrack>(track);
8059 mCallIRedirectionClients.add(info);
8060 }
8061 } else {
8062 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
8063 }
8064 return track;
8065 }
8066
8067 /**
8068 * @hide
8069 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
8070 * This can be used for functions like call screening or call audio redirection and is reserved
8071 * to system apps with privileged permission.
8072 * @param format the desired audio format for audio capture.
8073 *<p>Formats accepted are:
8074 * <ul>
8075 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8076 * <li><em>Channel mask</em> - Mono or Stereo </li>
8077 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8078 * </ul>
8079 *
8080 * @return The AudioRecord used for audio extraction
8081 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8082 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8083 * @throws NullPointerException if AudioFormat argument is null.
8084 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8085 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8086 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8087 * or MODE_COMMUNICATION_REDIRECT.
8088 */
8089 @TestApi
8090 @SystemApi
8091 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8092 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
8093 Objects.requireNonNull(format);
8094 checkCallRedirectionFormat(format, false /* isOutput */);
8095
8096 AudioRecord record = null;
8097 int redirectMode = getCallRedirectMode();
8098 if (redirectMode == CALL_REDIRECT_NONE) {
8099 throw new IllegalStateException(
8100 " not available in mode " + AudioSystem.modeToString(getMode()));
8101 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8102 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8103 }
8104
8105 record = new AudioRecord.Builder()
8106 .setAudioAttributes(new AudioAttributes.Builder()
8107 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
8108 .build())
8109 .setAudioFormat(format)
8110 .setCallRedirectionMode(redirectMode)
8111 .build();
8112
8113 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
8114 synchronized (mCallRedirectionLock) {
8115 if (mCallRedirectionModeListener == null) {
8116 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8117 try {
8118 addOnModeChangedListener(
8119 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8120 } catch (Exception e) {
8121 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8122 mCallRedirectionModeListener = null;
8123 throw new UnsupportedOperationException(" Cannot register mode listener ");
8124 }
8125 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8126 }
8127 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8128 info.redirectMode = redirectMode;
8129 info.trackOrRecord = new WeakReference<AudioRecord>(record);
8130 mCallIRedirectionClients.add(info);
8131 }
8132 } else {
8133 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
8134 }
8135 return record;
8136 }
8137
8138 class CallInjectionModeChangedListener implements OnModeChangedListener {
8139 @Override
8140 public void onModeChanged(@AudioMode int mode) {
8141 synchronized (mCallRedirectionLock) {
8142 final ArrayList<CallIRedirectionClientInfo> clientInfos =
8143 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
8144 for (CallIRedirectionClientInfo info : clientInfos) {
8145 Object trackOrRecord = info.trackOrRecord.get();
8146 if (trackOrRecord != null) {
8147 if ((info.redirectMode == CALL_REDIRECT_PSTN
8148 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
8149 && mode != MODE_CALL_REDIRECT)
8150 || (info.redirectMode == CALL_REDIRECT_VOIP
8151 && mode != MODE_IN_COMMUNICATION
8152 && mode != MODE_COMMUNICATION_REDIRECT)) {
8153 if (trackOrRecord instanceof AudioTrack) {
8154 AudioTrack track = (AudioTrack) trackOrRecord;
8155 track.release();
8156 } else {
8157 AudioRecord record = (AudioRecord) trackOrRecord;
8158 record.release();
8159 }
8160 mCallIRedirectionClients.remove(info);
8161 }
8162 }
8163 }
8164 if (mCallIRedirectionClients.isEmpty()) {
8165 try {
8166 if (mCallRedirectionModeListener != null) {
8167 removeOnModeChangedListener(mCallRedirectionModeListener);
8168 }
8169 } catch (Exception e) {
8170 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
8171 } finally {
8172 mCallRedirectionModeListener = null;
8173 mCallIRedirectionClients = null;
8174 }
8175 }
8176 }
8177 }
8178 }
8179
Paul McLeane3383cc2015-05-08 11:41:20 -07008180 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008181 // audio device connection-dependent muting
8182 /**
8183 * @hide
8184 * Mute a set of playback use cases until a given audio device is connected.
8185 * Automatically unmute upon connection of the device, or after the given timeout, whichever
8186 * happens first.
8187 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
8188 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
8189 * device connects
8190 * @param device the audio device expected to connect within the timeout duration
8191 * @param timeout the maximum amount of time to wait for the device connection
8192 * @param timeUnit the unit for the timeout
8193 * @throws IllegalStateException when trying to issue the command while another is already in
8194 * progress and hasn't been cancelled by
8195 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8196 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8197 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8198 */
8199 @SystemApi
8200 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8201 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8202 @NonNull AudioDeviceAttributes device,
8203 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8204 if (timeout <= 0) {
8205 throw new IllegalArgumentException("Timeout must be greater than 0");
8206 }
8207 Objects.requireNonNull(usagesToMute);
8208 if (usagesToMute.length == 0) {
8209 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8210 }
8211 Objects.requireNonNull(device);
8212 Objects.requireNonNull(timeUnit);
8213 try {
8214 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8215 } catch (RemoteException e) {
8216 throw e.rethrowFromSystemServer();
8217 }
8218 }
8219
8220 /**
8221 * @hide
8222 * Query which audio device, if any, is causing some playback use cases to be muted until it
8223 * connects.
8224 * @return the audio device used in
8225 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8226 * if there is no active muting command (either because the muting command was not issued
8227 * or because it timed out)
8228 */
8229 @SystemApi
8230 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8231 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8232 try {
8233 return getService().getMutingExpectedDevice();
8234 } catch (RemoteException e) {
8235 throw e.rethrowFromSystemServer();
8236 }
8237 }
8238
8239 /**
8240 * @hide
8241 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8242 * command.
8243 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8244 * command was issued.
8245 * @throws IllegalStateException when trying to issue the command for a device whose connection
8246 * is not anticipated by a previous call to
8247 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8248 */
8249 @SystemApi
8250 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8251 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8252 throws IllegalStateException {
8253 Objects.requireNonNull(device);
8254 try {
8255 getService().cancelMuteAwaitConnection(device);
8256 } catch (RemoteException e) {
8257 throw e.rethrowFromSystemServer();
8258 }
8259 }
8260
8261 /**
8262 * @hide
8263 * A callback class to receive events about the muting and unmuting of playback use cases
8264 * conditional on the upcoming connection of an audio device.
8265 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8266 */
8267 @SystemApi
8268 public abstract static class MuteAwaitConnectionCallback {
8269
8270 /**
8271 * An event where the expected audio device connected
8272 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8273 */
8274 public static final int EVENT_CONNECTION = 1;
8275 /**
8276 * An event where the expected audio device failed connect before the timeout happened
8277 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8278 */
8279 public static final int EVENT_TIMEOUT = 2;
8280 /**
8281 * An event where the {@code muteAwaitConnection()} command
8282 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
8283 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8284 */
8285 public static final int EVENT_CANCEL = 3;
8286
8287 /** @hide */
8288 @IntDef(flag = false, prefix = "EVENT_", value = {
8289 EVENT_CONNECTION,
8290 EVENT_TIMEOUT,
8291 EVENT_CANCEL }
8292 )
8293 @Retention(RetentionPolicy.SOURCE)
8294 public @interface UnmuteEvent {}
8295
8296 /**
8297 * Called when a number of playback use cases are muted in response to a call to
8298 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
8299 * @param device the audio device whose connection is expected. Playback use cases are
8300 * unmuted when that device connects
8301 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
8302 * playback use cases.
8303 */
8304 public void onMutedUntilConnection(
8305 @NonNull AudioDeviceAttributes device,
8306 @NonNull int[] mutedUsages) {}
8307
8308 /**
8309 * Called when an event occurred that caused playback uses cases to be unmuted
8310 * @param unmuteEvent the nature of the event
8311 * @param device the device that was expected to connect
8312 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
8313 * the event occurred
8314 */
8315 public void onUnmutedEvent(
8316 @UnmuteEvent int unmuteEvent,
8317 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
8318 }
8319
8320
8321 /**
8322 * @hide
8323 * Register a callback to receive updates on the playback muting conditional on a specific
8324 * audio device connection.
8325 * @param executor the {@link Executor} handling the callback
8326 * @param callback the callback to register
8327 */
8328 @SystemApi
8329 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8330 public void registerMuteAwaitConnectionCallback(
8331 @NonNull @CallbackExecutor Executor executor,
8332 @NonNull MuteAwaitConnectionCallback callback) {
8333 synchronized (mMuteAwaitConnectionListenerLock) {
8334 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8335 MuteAwaitConnectionDispatcherStub> res =
8336 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
8337 executor, callback, mMuteAwaitConnectionListeners,
8338 mMuteAwaitConnDispatcherStub,
8339 () -> new MuteAwaitConnectionDispatcherStub(),
8340 stub -> stub.register(true));
8341 mMuteAwaitConnectionListeners = res.first;
8342 mMuteAwaitConnDispatcherStub = res.second;
8343 }
8344 }
8345
8346 /**
8347 * @hide
8348 * Unregister a previously registered callback for playback muting conditional on device
8349 * connection.
8350 * @param callback the callback to unregister
8351 */
8352 @SystemApi
8353 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8354 public void unregisterMuteAwaitConnectionCallback(
8355 @NonNull MuteAwaitConnectionCallback callback) {
8356 synchronized (mMuteAwaitConnectionListenerLock) {
8357 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8358 MuteAwaitConnectionDispatcherStub> res =
8359 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
8360 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
8361 stub -> stub.register(false));
8362 mMuteAwaitConnectionListeners = res.first;
8363 mMuteAwaitConnDispatcherStub = res.second;
8364 }
8365 }
8366
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008367 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008368 * Add UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008369 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008370 * @param assistantUids UIDs of the services that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008371 *
8372 * @hide
8373 */
8374 @SystemApi
8375 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008376 public void addAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008377 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008378 getService().addAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008379 } catch (RemoteException e) {
8380 throw e.rethrowFromSystemServer();
8381 }
8382 }
8383
8384 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008385 * Remove UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008386 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008387 * @param assistantUids UIDs of the services that should be remove.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008388 *
8389 * @hide
8390 */
8391 @SystemApi
8392 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008393 public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008394 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008395 getService().removeAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008396 } catch (RemoteException e) {
8397 throw e.rethrowFromSystemServer();
8398 }
8399 }
8400
8401 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008402 * Get the assistants UIDs that been added with the
8403 * {@link #addAssistantServicesUids(int[])} and not yet removed with
8404 * {@link #removeAssistantServicesUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008405 *
Oscar Azucena3ae33762022-03-04 04:44:59 +00008406 * <p> Note that during native audioserver crash and after boot up the list of assistant
8407 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
8408 * Just after user switch, the list of assistant will also reset to empty.
8409 * In both cases,The component's UID of the assistiant role or assistant setting will be
8410 * automitically added to the list by the audio service.
8411 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008412 * @return array of assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008413 *
8414 * @hide
8415 */
8416 @SystemApi
8417 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008418 public @NonNull int[] getAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008419 try {
8420 int[] uids = getService().getAssistantServicesUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00008421 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008422 } catch (RemoteException e) {
8423 throw e.rethrowFromSystemServer();
8424 }
8425 }
8426
8427 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008428 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
8429 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
8430 * In this manner calling the API with an empty array will remove all UIDs previously set.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008431 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008432 * @param assistantUids UIDs of the services that can be considered active assistant. Can be
8433 * an empty array, for this no UID will be considered active.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008434 *
8435 * <p> Note that during audio service crash reset and after boot up the list of active assistant
Oscar Azucena88467fe2022-02-15 21:55:11 +00008436 * 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 -08008437 * Just after user switch the list of active assistant will also reset to empty.
8438 *
8439 * @hide
8440 */
8441 @SystemApi
8442 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008443 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008444 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008445 getService().setActiveAssistantServiceUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008446 } catch (RemoteException e) {
8447 throw e.rethrowFromSystemServer();
8448 }
8449 }
8450
8451 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008452 * Get active assistant UIDs last set with the
8453 * {@link #setActiveAssistantServiceUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008454 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008455 * @return array of active assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008456 *
8457 * @hide
8458 */
8459 @SystemApi
8460 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008461 public @NonNull int[] getActiveAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008462 try {
8463 int[] uids = getService().getActiveAssistantServiceUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00008464 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008465 } catch (RemoteException e) {
8466 throw e.rethrowFromSystemServer();
8467 }
8468 }
8469
jiabinfe6b7f12022-02-04 18:45:44 +00008470 /**
8471 * Returns the audio HAL version in the form MAJOR.MINOR. If there is no audio HAL found, null
8472 * will be returned.
8473 *
8474 * @hide
8475 */
8476 @TestApi
8477 public static @Nullable String getHalVersion() {
8478 try {
8479 return getService().getHalVersion();
8480 } catch (RemoteException e) {
8481 Log.e(TAG, "Error querying getHalVersion", e);
8482 throw e.rethrowFromSystemServer();
8483 }
8484 }
8485
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008486 private final Object mMuteAwaitConnectionListenerLock = new Object();
8487
8488 @GuardedBy("mMuteAwaitConnectionListenerLock")
8489 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
8490 mMuteAwaitConnectionListeners;
8491
8492 @GuardedBy("mMuteAwaitConnectionListenerLock")
8493 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
8494
8495 private final class MuteAwaitConnectionDispatcherStub
8496 extends IMuteAwaitConnectionCallback.Stub {
8497 public void register(boolean register) {
8498 try {
8499 getService().registerMuteAwaitConnectionDispatcher(this, register);
8500 } catch (RemoteException e) {
8501 throw e.rethrowFromSystemServer();
8502 }
8503 }
8504
8505 @Override
8506 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8507 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
8508 int[] mutedUsages) {
8509 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8510 mMuteAwaitConnectionListenerLock,
8511 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
8512 }
8513
8514 @Override
8515 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8516 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
8517 int[] mutedUsages) {
8518 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8519 mMuteAwaitConnectionListenerLock,
8520 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
8521 }
8522 }
8523
8524 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07008525 // Inner classes
8526 //--------------------
8527 /**
8528 * Helper class to handle the forwarding of native events to the appropriate listener
8529 * (potentially) handled in a different thread.
8530 */
8531 private class NativeEventHandlerDelegate {
8532 private final Handler mHandler;
8533
Paul McLean03346882015-05-12 15:36:56 -07008534 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07008535 Handler handler) {
8536 // find the looper for our new event handler
8537 Looper looper;
8538 if (handler != null) {
8539 looper = handler.getLooper();
8540 } else {
8541 // no given handler, use the looper the addListener call was called in
8542 looper = Looper.getMainLooper();
8543 }
8544
8545 // construct the event handler with this looper
8546 if (looper != null) {
8547 // implement the event handler delegate
8548 mHandler = new Handler(looper) {
8549 @Override
8550 public void handleMessage(Message msg) {
8551 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07008552 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07008553 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07008554 if (callback != null) {
8555 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07008556 }
8557 break;
Paul McLean03346882015-05-12 15:36:56 -07008558
8559 case MSG_DEVICES_DEVICES_REMOVED:
8560 if (callback != null) {
8561 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
8562 }
8563 break;
8564
Paul McLeane3383cc2015-05-08 11:41:20 -07008565 default:
8566 Log.e(TAG, "Unknown native event type: " + msg.what);
8567 break;
8568 }
8569 }
8570 };
8571 } else {
8572 mHandler = null;
8573 }
8574 }
8575
8576 Handler getHandler() {
8577 return mHandler;
8578 }
8579 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08008580}