blob: ead2b1d6316d8fb212d8aa77298a020003803135 [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;
Oscar Azucena3ef3f582022-01-31 19:07:14 -080094import java.util.stream.Collectors;
Eric Laurent700e7342014-05-02 18:33:15 -070095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096/**
97 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060099@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100public class AudioManager {
101
Marco Nelissen29f16932015-04-17 09:50:56 -0700102 private Context mOriginalContext;
103 private Context mApplicationContext;
Joe Onorato86f67862010-11-05 18:57:34 -0700104 private long mVolumeKeyUpTime;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800105 private static final String TAG = "AudioManager";
106 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800107 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200108 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
109 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110
jiabin0f3339c2021-07-09 11:50:07 -0700111 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 /**
114 * Broadcast intent, a hint for applications that audio is about to become
115 * 'noisy' due to a change in audio outputs. For example, this intent may
116 * be sent when a wired headset is unplugged, or when an A2DP audio
117 * sink is disconnected, and the audio system is about to automatically
118 * switch audio route to the speaker. Applications that are controlling
119 * audio streams may consider pausing, reducing volume or some other action
120 * on receipt of this intent so as not to surprise the user with audio
121 * from the speaker.
122 */
123 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
124 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
125
126 /**
127 * Sticky broadcast intent action indicating that the ringer mode has
128 * changed. Includes the new ringer mode.
129 *
130 * @see #EXTRA_RINGER_MODE
131 */
132 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
133 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
134
135 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500136 * @hide
137 * Sticky broadcast intent action indicating that the internal ringer mode has
138 * changed. Includes the new ringer mode.
139 *
140 * @see #EXTRA_RINGER_MODE
141 */
142 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
143 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
144 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
145
146 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 * The new ringer mode.
148 *
149 * @see #RINGER_MODE_CHANGED_ACTION
150 * @see #RINGER_MODE_NORMAL
151 * @see #RINGER_MODE_SILENT
152 * @see #RINGER_MODE_VIBRATE
153 */
154 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
155
156 /**
157 * Broadcast intent action indicating that the vibrate setting has
158 * changed. Includes the vibrate type and its new setting.
159 *
160 * @see #EXTRA_VIBRATE_TYPE
161 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700162 * @deprecated Applications should maintain their own vibrate policy based on
163 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 */
165 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500166 public static final String VIBRATE_SETTING_CHANGED_ACTION =
167 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168
169 /**
170 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700171 * Includes the stream, the new volume and previous volumes.
172 * Notes:
173 * - for internal platform use only, do not make public,
174 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 *
176 * @see #EXTRA_VOLUME_STREAM_TYPE
177 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800178 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 */
180 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100181 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
183
184 /**
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800185 * @hide Broadcast intent when the volume for a particular stream type changes.
186 * Includes the stream, the new volume and previous volumes.
187 * Notes:
188 * - for internal platform use only, do not make public,
189 * - never used for "remote" volume changes
190 *
191 * @see #EXTRA_VOLUME_STREAM_TYPE
192 * @see #EXTRA_VOLUME_STREAM_VALUE
193 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
194 */
195 @SystemApi
196 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
197 @SuppressLint("ActionValue")
198 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
199
200 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400201 * @hide Broadcast intent when the devices for a particular stream type changes.
202 * Includes the stream, the new devices and previous devices.
203 * Notes:
204 * - for internal platform use only, do not make public,
205 * - never used for "remote" volume changes
206 *
207 * @see #EXTRA_VOLUME_STREAM_TYPE
208 * @see #EXTRA_VOLUME_STREAM_DEVICES
209 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
210 * @see #getDevicesForStream
211 */
212 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
213 public static final String STREAM_DEVICES_CHANGED_ACTION =
214 "android.media.STREAM_DEVICES_CHANGED_ACTION";
215
216 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800217 * @hide Broadcast intent when a stream mute state changes.
218 * Includes the stream that changed and the new mute state
219 *
220 * @see #EXTRA_VOLUME_STREAM_TYPE
221 * @see #EXTRA_STREAM_VOLUME_MUTED
222 */
223 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
224 public static final String STREAM_MUTE_CHANGED_ACTION =
225 "android.media.STREAM_MUTE_CHANGED_ACTION";
226
227 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500228 * @hide Broadcast intent when the master mute state changes.
229 * Includes the the new volume
230 *
231 * @see #EXTRA_MASTER_VOLUME_MUTED
232 */
233 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
234 public static final String MASTER_MUTE_CHANGED_ACTION =
235 "android.media.MASTER_MUTE_CHANGED_ACTION";
236
237 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 * The new vibrate setting for a particular type.
239 *
240 * @see #VIBRATE_SETTING_CHANGED_ACTION
241 * @see #EXTRA_VIBRATE_TYPE
242 * @see #VIBRATE_SETTING_ON
243 * @see #VIBRATE_SETTING_OFF
244 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700245 * @deprecated Applications should maintain their own vibrate policy based on
246 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 */
248 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
249
250 /**
251 * The vibrate type whose setting has changed.
252 *
253 * @see #VIBRATE_SETTING_CHANGED_ACTION
254 * @see #VIBRATE_TYPE_NOTIFICATION
255 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700256 * @deprecated Applications should maintain their own vibrate policy based on
257 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 */
259 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
260
261 /**
262 * @hide The stream type for the volume changed intent.
263 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800264 @SystemApi
265 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
267
268 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700269 * @hide
270 * The stream type alias for the volume changed intent.
271 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
272 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
273 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
274 * {@link #STREAM_MUSIC} on others (e.g. a television).
275 */
276 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
277 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
278
279 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 * @hide The volume associated with the stream for the volume changed intent.
281 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800282 @SystemApi
283 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 public static final String EXTRA_VOLUME_STREAM_VALUE =
285 "android.media.EXTRA_VOLUME_STREAM_VALUE";
286
Eric Laurent9ce379a2010-02-16 06:00:26 -0800287 /**
288 * @hide The previous volume associated with the stream for the volume changed intent.
289 */
290 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
291 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
292
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500293 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400294 * @hide The devices associated with the stream for the stream devices changed intent.
295 */
296 public static final String EXTRA_VOLUME_STREAM_DEVICES =
297 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
298
299 /**
300 * @hide The previous devices associated with the stream for the stream devices changed intent.
301 */
302 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
303 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
304
305 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500306 * @hide The new master volume mute state for the master mute changed intent.
307 * Value is boolean
308 */
309 public static final String EXTRA_MASTER_VOLUME_MUTED =
310 "android.media.EXTRA_MASTER_VOLUME_MUTED";
311
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700312 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800313 * @hide The new stream volume mute state for the stream mute changed intent.
314 * Value is boolean
315 */
316 public static final String EXTRA_STREAM_VOLUME_MUTED =
317 "android.media.EXTRA_STREAM_VOLUME_MUTED";
318
319 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700320 * Broadcast Action: Wired Headset plugged in or unplugged.
321 *
322 * You <em>cannot</em> receive this through components declared
323 * in manifests, only by explicitly registering for it with
324 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
325 * Context.registerReceiver()}.
326 *
327 * <p>The intent will have the following extra values:
328 * <ul>
329 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
330 * <li><em>name</em> - Headset type, human readable string </li>
331 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
332 * </ul>
333 * </ul>
334 */
335 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
336 public static final String ACTION_HEADSET_PLUG =
337 "android.intent.action.HEADSET_PLUG";
338
339 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200340 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700341 *
342 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
343 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
344 * <p>It can only be received by explicitly registering for it with
345 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
346 */
347 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
348 public static final String ACTION_HDMI_AUDIO_PLUG =
349 "android.media.action.HDMI_AUDIO_PLUG";
350
351 /**
352 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
353 * or unplugged.
354 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
355 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700356 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700357
358 /**
359 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
360 * supported by the HDMI device.
361 * The corresponding integer value is only available when the device is plugged in (as expressed
362 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
363 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700364 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700365
366 /**
367 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
368 * the connected HDMI device.
369 * The corresponding array of encoding values is only available when the device is plugged in
370 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
371 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
372 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
373 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700374 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700375
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700376 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700378 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700380 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700382 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700384 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700386 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700388 /** @hide Used to identify the volume of audio streams for phone calls when connected
389 * to bluetooth */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800390 @SystemApi
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700392 /** @hide Used to identify the volume of audio streams for enforced system sounds
393 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100394 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700395 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700396 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700397 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700398 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
399 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100400 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700401 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800402 /** Used to identify the volume of audio streams for accessibility prompts */
403 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000404 /** @hide Used to identify the volume of audio streams for virtual assistant */
405 @SystemApi
406 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
407 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 /** Number of audio streams */
410 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700411 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 */
Eric Laurenta553c252009-07-17 12:17:14 -0700413 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414
Paul McLeand6f87c82021-03-31 13:02:41 -0600415 /** @hide */
416 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
417 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
418 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
419 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
420
421 /** @hide */
422 @TestApi
423 public static final int[] getPublicStreamTypes() {
424 return PUBLIC_STREAM_TYPES;
425 }
426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 /**
428 * Increase the ringer volume.
429 *
430 * @see #adjustVolume(int, int)
431 * @see #adjustStreamVolume(int, int, int)
432 */
433 public static final int ADJUST_RAISE = 1;
434
435 /**
436 * Decrease the ringer volume.
437 *
438 * @see #adjustVolume(int, int)
439 * @see #adjustStreamVolume(int, int, int)
440 */
441 public static final int ADJUST_LOWER = -1;
442
443 /**
444 * Maintain the previous ringer volume. This may be useful when needing to
445 * show the volume toast without actually modifying the volume.
446 *
447 * @see #adjustVolume(int, int)
448 * @see #adjustStreamVolume(int, int, int)
449 */
450 public static final int ADJUST_SAME = 0;
451
RoboErik4197cb62015-01-21 15:45:32 -0800452 /**
453 * Mute the volume. Has no effect if the stream is already muted.
454 *
455 * @see #adjustVolume(int, int)
456 * @see #adjustStreamVolume(int, int, int)
457 */
458 public static final int ADJUST_MUTE = -100;
459
460 /**
461 * Unmute the volume. Has no effect if the stream is not muted.
462 *
463 * @see #adjustVolume(int, int)
464 * @see #adjustStreamVolume(int, int, int)
465 */
466 public static final int ADJUST_UNMUTE = 100;
467
468 /**
469 * Toggle the mute state. If muted the stream will be unmuted. If not muted
470 * the stream will be muted.
471 *
472 * @see #adjustVolume(int, int)
473 * @see #adjustStreamVolume(int, int, int)
474 */
475 public static final int ADJUST_TOGGLE_MUTE = 101;
476
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700477 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800478 @IntDef(flag = false, prefix = "ADJUST", value = {
479 ADJUST_RAISE,
480 ADJUST_LOWER,
481 ADJUST_SAME,
482 ADJUST_MUTE,
483 ADJUST_UNMUTE,
484 ADJUST_TOGGLE_MUTE }
485 )
486 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800487 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800488
489 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700490 public static final String adjustToString(int adj) {
491 switch (adj) {
492 case ADJUST_RAISE: return "ADJUST_RAISE";
493 case ADJUST_LOWER: return "ADJUST_LOWER";
494 case ADJUST_SAME: return "ADJUST_SAME";
495 case ADJUST_MUTE: return "ADJUST_MUTE";
496 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
497 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
498 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
499 }
500 }
501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 // Flags should be powers of 2!
503
504 /**
505 * Show a toast containing the current volume.
506 *
507 * @see #adjustStreamVolume(int, int, int)
508 * @see #adjustVolume(int, int)
509 * @see #setStreamVolume(int, int, int)
510 * @see #setRingerMode(int)
511 */
512 public static final int FLAG_SHOW_UI = 1 << 0;
513
514 /**
515 * Whether to include ringer modes as possible options when changing volume.
516 * For example, if true and volume level is 0 and the volume is adjusted
517 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
518 * vibrate mode.
519 * <p>
520 * By default this is on for the ring stream. If this flag is included,
521 * this behavior will be present regardless of the stream type being
522 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700523 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 * @see #adjustVolume(int, int)
525 * @see #adjustStreamVolume(int, int, int)
526 */
527 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
528
529 /**
530 * Whether to play a sound when changing the volume.
531 * <p>
532 * If this is given to {@link #adjustVolume(int, int)} or
533 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
534 * in some cases (for example, the decided stream type is not
535 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
536 * downward).
537 *
538 * @see #adjustStreamVolume(int, int, int)
539 * @see #adjustVolume(int, int)
540 * @see #setStreamVolume(int, int, int)
541 */
542 public static final int FLAG_PLAY_SOUND = 1 << 2;
543
544 /**
545 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
546 * changing volume).
547 */
548 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
549
550 /**
551 * Whether to vibrate if going into the vibrate ringer mode.
552 */
553 public static final int FLAG_VIBRATE = 1 << 4;
554
555 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700556 * Indicates to VolumePanel that the volume slider should be disabled as user
557 * cannot change the stream volume
558 * @hide
559 */
560 public static final int FLAG_FIXED_VOLUME = 1 << 5;
561
562 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700563 * Indicates the volume set/adjust call is for Bluetooth absolute volume
564 * @hide
565 */
Roopa Sattirajufb933242022-01-30 13:27:58 -0800566 @SystemApi
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700567 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
568
569 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400570 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
571 * @hide
572 */
573 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
574
575 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900576 * Indicates the volume call is for Hdmi Cec system audio volume
577 * @hide
578 */
579 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
580
581 /**
RoboErik3c45c292014-07-08 16:47:31 -0700582 * Indicates that this should only be handled if media is actively playing.
583 * @hide
584 */
585 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
586
587 /**
John Spurlock35134602014-07-24 18:10:48 -0400588 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
589 * @hide
590 */
591 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
592
593 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500594 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
595 * @hide
596 */
597 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
598
John Spurlockb94f2d62015-03-17 14:11:57 -0400599 /**
600 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900601 * This flag can be used in the places in order to denote (or check) that a volume adjustment
602 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400603 * @hide
604 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900605 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900606 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400607
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900608 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100609 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200610 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100611 ENCODED_SURROUND_OUTPUT_AUTO,
612 ENCODED_SURROUND_OUTPUT_NEVER,
613 ENCODED_SURROUND_OUTPUT_ALWAYS,
614 ENCODED_SURROUND_OUTPUT_MANUAL
615 })
616 @Retention(RetentionPolicy.SOURCE)
617 public @interface EncodedSurroundOutputMode {}
618
619 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200620 * The mode for surround sound formats is unknown.
621 */
622 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
623
624 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100625 * The surround sound formats are available for use if they are detected. This is the default
626 * mode.
627 */
628 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
629
630 /**
631 * The surround sound formats are NEVER available, even if they are detected by the hardware.
632 * Those formats will not be reported.
633 */
634 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
635
636 /**
637 * The surround sound formats are ALWAYS available, even if they are not detected by the
638 * hardware. Those formats will be reported as part of the HDMI output capability.
639 * Applications are then free to use either PCM or encoded output.
640 */
641 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
642
643 /**
644 * Surround sound formats are available according to the choice of user, even if they are not
645 * detected by the hardware. Those formats will be reported as part of the HDMI output
646 * capability. Applications are then free to use either PCM or encoded output.
647 */
648 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
649
650 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900651 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900652 FLAG_SHOW_UI,
653 FLAG_ALLOW_RINGER_MODES,
654 FLAG_PLAY_SOUND,
655 FLAG_REMOVE_SOUND_AND_VIBRATE,
656 FLAG_VIBRATE,
657 FLAG_FIXED_VOLUME,
658 FLAG_BLUETOOTH_ABS_VOLUME,
659 FLAG_SHOW_SILENT_HINT,
660 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
661 FLAG_ACTIVE_MEDIA_ONLY,
662 FLAG_SHOW_UI_WARNINGS,
663 FLAG_SHOW_VIBRATE_HINT,
664 FLAG_FROM_KEY,
665 })
666 @Retention(RetentionPolicy.SOURCE)
667 public @interface Flags {}
668
Hyundo Moonca0080d2018-12-26 16:16:55 +0900669 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
670 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
671
672 static {
673 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
674 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
675 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
676 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
677 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
678 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
679 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
680 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
681 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
682 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
683 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
684 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
685 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
686 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500687
688 /** @hide */
689 public static String flagsToString(int flags) {
690 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900691 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
692 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500693 if ((flags & flag) != 0) {
694 if (sb.length() > 0) {
695 sb.append(',');
696 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900697 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500698 flags &= ~flag;
699 }
700 }
701 if (flags != 0) {
702 if (sb.length() > 0) {
703 sb.append(',');
704 }
705 sb.append(flags);
706 }
707 return sb.toString();
708 }
709
710 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 * Ringer mode that will be silent and will not vibrate. (This overrides the
712 * vibrate setting.)
713 *
714 * @see #setRingerMode(int)
715 * @see #getRingerMode()
716 */
717 public static final int RINGER_MODE_SILENT = 0;
718
719 /**
720 * Ringer mode that will be silent and will vibrate. (This will cause the
721 * phone ringer to always vibrate, but the notification vibrate to only
722 * vibrate if set.)
723 *
724 * @see #setRingerMode(int)
725 * @see #getRingerMode()
726 */
727 public static final int RINGER_MODE_VIBRATE = 1;
728
729 /**
730 * Ringer mode that may be audible and may vibrate. It will be audible if
731 * the volume before changing out of this mode was audible. It will vibrate
732 * if the vibrate setting is on.
733 *
734 * @see #setRingerMode(int)
735 * @see #getRingerMode()
736 */
737 public static final int RINGER_MODE_NORMAL = 2;
738
John Spurlock97559372014-10-24 16:27:36 -0400739 /**
740 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
741 * @hide
742 */
743 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 /**
746 * Vibrate type that corresponds to the ringer.
747 *
748 * @see #setVibrateSetting(int, int)
749 * @see #getVibrateSetting(int)
750 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700751 * @deprecated Applications should maintain their own vibrate policy based on
752 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 */
754 public static final int VIBRATE_TYPE_RINGER = 0;
755
756 /**
757 * Vibrate type that corresponds to notifications.
758 *
759 * @see #setVibrateSetting(int, int)
760 * @see #getVibrateSetting(int)
761 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700762 * @deprecated Applications should maintain their own vibrate policy based on
763 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 */
765 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
766
767 /**
768 * Vibrate setting that suggests to never vibrate.
769 *
770 * @see #setVibrateSetting(int, int)
771 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700772 * @deprecated Applications should maintain their own vibrate policy based on
773 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 */
775 public static final int VIBRATE_SETTING_OFF = 0;
776
777 /**
778 * Vibrate setting that suggests to vibrate when possible.
779 *
780 * @see #setVibrateSetting(int, int)
781 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700782 * @deprecated Applications should maintain their own vibrate policy based on
783 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 */
785 public static final int VIBRATE_SETTING_ON = 1;
786
787 /**
788 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
789 * mode.
790 *
791 * @see #setVibrateSetting(int, int)
792 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700793 * @deprecated Applications should maintain their own vibrate policy based on
794 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 */
796 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
797
798 /**
799 * Suggests using the default stream type. This may not be used in all
800 * places a stream type is needed.
801 */
802 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
803
804 private static IAudioService sService;
805
806 /**
807 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800808 * For test purposes only, will throw NPE with some methods that require a Context.
809 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000810 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800811 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800812 }
813
814 /**
815 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100817 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700819 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821
Marco Nelissen29f16932015-04-17 09:50:56 -0700822 private Context getContext() {
823 if (mApplicationContext == null) {
824 setContext(mOriginalContext);
825 }
826 if (mApplicationContext != null) {
827 return mApplicationContext;
828 }
829 return mOriginalContext;
830 }
831
832 private void setContext(Context context) {
833 mApplicationContext = context.getApplicationContext();
834 if (mApplicationContext != null) {
835 mOriginalContext = null;
836 } else {
837 mOriginalContext = context;
838 }
jiabin0f3339c2021-07-09 11:50:07 -0700839 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700840 }
841
Mathew Inwood31a792a2018-08-17 08:54:26 +0100842 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700843 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 {
845 if (sService != null) {
846 return sService;
847 }
848 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
849 sService = IAudioService.Stub.asInterface(b);
850 return sService;
851 }
852
853 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700854 * Sends a simulated key event for a media button.
855 * To simulate a key press, you must first send a KeyEvent built with a
856 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
857 * action.
858 * <p>The key event will be sent to the current media key event consumer which registered with
859 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
860 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
861 * {@link KeyEvent#KEYCODE_MUTE},
862 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
863 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
864 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
865 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
866 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
867 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
868 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
869 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
870 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
871 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
872 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
873 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
874 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700875 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700876 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700877 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700878 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700879 }
880
881 /**
882 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700883 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800884 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700885 /*
886 * If the user hits another key within the play sound delay, then
887 * cancel the sound
888 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800889 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700890 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
891 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500892 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700893 /*
894 * The user has hit another key during the delay (e.g., 300ms)
895 * since the last volume key up, so cancel any sounds.
896 */
John Spurlockee5ad722015-03-03 16:17:21 -0500897 adjustSuggestedStreamVolume(ADJUST_SAME,
898 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700899 }
900 }
901
902 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700903 * Indicates if the device implements a fixed volume policy.
904 * <p>Some devices may not have volume control and may operate at a fixed volume,
905 * and may not enable muting or changing the volume of audio streams.
906 * This method will return true on such devices.
907 * <p>The following APIs have no effect when volume is fixed:
908 * <ul>
909 * <li> {@link #adjustVolume(int, int)}
910 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
911 * <li> {@link #adjustStreamVolume(int, int, int)}
912 * <li> {@link #setStreamVolume(int, int, int)}
913 * <li> {@link #setRingerMode(int)}
914 * <li> {@link #setStreamSolo(int, boolean)}
915 * <li> {@link #setStreamMute(int, boolean)}
916 * </ul>
917 */
918 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700919 boolean res = false;
920 try {
921 res = getService().isVolumeFixed();
922 } catch (RemoteException e) {
923 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700924 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700925 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700926 }
927
928 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700930 * <p>
931 * This method should only be used by applications that replace the platform-wide
932 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700933 * <p>This method has no effect if the device implements a fixed volume policy
934 * as indicated by {@link #isVolumeFixed()}.
935 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
936 * unless the app has been granted Do Not Disturb Access.
937 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 *
939 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800940 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
941 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 * @param direction The direction to adjust the volume. One of
943 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
944 * {@link #ADJUST_SAME}.
945 * @param flags One or more flags.
946 * @see #adjustVolume(int, int)
947 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700948 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
949 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 */
951 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700952 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 try {
John Wu4f7e5102021-06-22 17:29:11 +0000954 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
955 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700957 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 }
959 }
960
961 /**
962 * Adjusts the volume of the most relevant stream. For example, if a call is
963 * active, it will have the highest priority regardless of if the in-call
964 * screen is showing. Another example, if music is playing in the background
965 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700966 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800967 * This method should only be used by applications that replace the
968 * platform-wide management of audio settings or the main telephony
969 * application.
970 * <p>
971 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700972 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800973 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800975 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
976 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
977 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 * @param flags One or more flags.
979 * @see #adjustSuggestedStreamVolume(int, int, int)
980 * @see #adjustStreamVolume(int, int, int)
981 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700982 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 */
984 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700985 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500986 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 }
988
989 /**
990 * Adjusts the volume of the most relevant stream, or the given fallback
991 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700992 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800993 * This method should only be used by applications that replace the
994 * platform-wide management of audio settings or the main telephony
995 * application.
996 * <p>
997 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700998 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800999 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001001 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1002 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1003 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001005 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1006 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 * @param flags One or more flags.
1008 * @see #adjustVolume(int, int)
1009 * @see #adjustStreamVolume(int, int, int)
1010 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001011 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 */
1013 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001014 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001015 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001016 }
1017
John Spurlockee5ad722015-03-03 16:17:21 -05001018 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001019 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -07001020 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001021 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001022 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001023 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001024 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001025 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001026 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001027 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 }
1029 }
1030
1031 /**
1032 * Returns the current ringtone mode.
1033 *
1034 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1035 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1036 * @see #setRingerMode(int)
1037 */
1038 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001039 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001041 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001043 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 }
1045 }
1046
1047 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001048 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1049 *
1050 * @return true if the incoming phone call ringtone is configured to gradually increase its
1051 * volume, false otherwise.
1052 */
1053 public boolean isRampingRingerEnabled() {
1054 return Settings.System.getInt(getContext().getContentResolver(),
1055 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1056 }
1057
1058 /**
1059 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1060 *
1061 * @see #isRampingRingerEnabled()
1062 * @hide
1063 */
1064 @TestApi
1065 public void setRampingRingerEnabled(boolean enabled) {
1066 Settings.System.putInt(getContext().getContentResolver(),
1067 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1068 }
1069
1070 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001071 * Checks valid ringer mode values.
1072 *
1073 * @return true if the ringer mode indicated is valid, false otherwise.
1074 *
1075 * @see #setRingerMode(int)
1076 * @hide
1077 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001078 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001079 public static boolean isValidRingerMode(int ringerMode) {
1080 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1081 return false;
1082 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001083 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001084 try {
1085 return service.isValidRingerMode(ringerMode);
1086 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001087 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001088 }
Eric Laurent72668b22011-07-19 16:04:27 -07001089 }
1090
1091 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 * Returns the maximum volume index for a particular stream.
1093 *
1094 * @param streamType The stream type whose maximum volume index is returned.
1095 * @return The maximum valid volume index for the stream.
1096 * @see #getStreamVolume(int)
1097 */
1098 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001099 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001101 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001103 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 }
1105 }
1106
1107 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001108 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001109 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1110 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1111 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1112 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1113 * @return The minimum valid volume index for the stream.
1114 * @see #getStreamVolume(int)
1115 */
1116 public int getStreamMinVolume(int streamType) {
1117 if (!isPublicStreamType(streamType)) {
1118 throw new IllegalArgumentException("Invalid stream type " + streamType);
1119 }
1120 return getStreamMinVolumeInt(streamType);
1121 }
1122
1123 /**
1124 * @hide
1125 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001126 * @param streamType The stream type whose minimum volume index is returned.
1127 * @return The minimum valid volume index for the stream.
1128 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001129 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001130 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001131 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001132 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001133 try {
1134 return service.getStreamMinVolume(streamType);
1135 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001136 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001137 }
1138 }
1139
1140 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 * Returns the current volume index for a particular stream.
1142 *
1143 * @param streamType The stream type whose volume index is returned.
1144 * @return The current volume index for the stream.
1145 * @see #getStreamMaxVolume(int)
1146 * @see #setStreamVolume(int, int, int)
1147 */
1148 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001149 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001151 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001153 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 }
1155 }
1156
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001157 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1158 private static final float VOLUME_MIN_DB = -758.0f;
1159
1160 /** @hide */
1161 @IntDef(flag = false, prefix = "STREAM", value = {
1162 STREAM_VOICE_CALL,
1163 STREAM_SYSTEM,
1164 STREAM_RING,
1165 STREAM_MUSIC,
1166 STREAM_ALARM,
1167 STREAM_NOTIFICATION,
1168 STREAM_DTMF,
1169 STREAM_ACCESSIBILITY }
1170 )
1171 @Retention(RetentionPolicy.SOURCE)
1172 public @interface PublicStreamTypes {}
1173
1174 /**
1175 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1176 * the given type of audio output device.
1177 * @param streamType stream type for which the volume is queried.
1178 * @param index the volume index for which the volume is queried. The index value must be
1179 * between the minimum and maximum index values for the given stream type (see
1180 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1181 * @param deviceType the type of audio output device for which volume is queried.
1182 * @return a volume expressed in dB.
1183 * A negative value indicates the audio signal is attenuated. A typical maximum value
1184 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1185 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1186 */
1187 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1188 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1189 if (!isPublicStreamType(streamType)) {
1190 throw new IllegalArgumentException("Invalid stream type " + streamType);
1191 }
1192 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1193 throw new IllegalArgumentException("Invalid stream volume index " + index);
1194 }
1195 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1196 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1197 }
1198 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1199 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1200 if (gain <= VOLUME_MIN_DB) {
1201 return Float.NEGATIVE_INFINITY;
1202 } else {
1203 return gain;
1204 }
1205 }
1206
1207 private static boolean isPublicStreamType(int streamType) {
1208 switch (streamType) {
1209 case STREAM_VOICE_CALL:
1210 case STREAM_SYSTEM:
1211 case STREAM_RING:
1212 case STREAM_MUSIC:
1213 case STREAM_ALARM:
1214 case STREAM_NOTIFICATION:
1215 case STREAM_DTMF:
1216 case STREAM_ACCESSIBILITY:
1217 return true;
1218 default:
1219 return false;
1220 }
1221 }
1222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001224 * Get last audible volume before stream was muted.
1225 *
1226 * @hide
1227 */
wescandee178f8f2021-10-19 20:15:09 +02001228 @SystemApi
1229 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001230 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001231 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001232 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001233 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001234 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001235 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001236 }
1237 }
1238
1239 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001240 * Get the stream type whose volume is driving the UI sounds volume.
1241 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001242 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001243 * @hide
1244 */
John Spurlockee5ad722015-03-03 16:17:21 -05001245 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001246 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001247 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001248 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001249 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001250 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001251 }
1252 }
1253
1254 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 * Sets the ringer mode.
1256 * <p>
1257 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1258 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1259 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001260 * <p>This method has no effect if the device implements a fixed volume policy
1261 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001262 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1263 * unless the app has been granted Do Not Disturb Access.
1264 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1266 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1267 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001268 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 */
1270 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001271 if (!isValidRingerMode(ringerMode)) {
1272 return;
1273 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001274 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001276 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001278 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 }
1280 }
1281
1282 /**
1283 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001284 * <p>This method has no effect if the device implements a fixed volume policy
1285 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001286 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1287 * the app has been granted Do Not Disturb Access.
1288 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 * @param streamType The stream whose volume index should be set.
1290 * @param index The volume index to set. See
1291 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1292 * @param flags One or more flags.
1293 * @see #getStreamMaxVolume(int)
1294 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001295 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001296 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1297 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 */
1299 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001300 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 try {
John Wu4f7e5102021-06-22 17:29:11 +00001302 service.setStreamVolumeWithAttribution(streamType, index, flags,
1303 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001305 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 }
1307 }
1308
1309 /**
François Gaffie9c362102018-09-21 17:43:52 +02001310 * Sets the volume index for a particular {@link AudioAttributes}.
1311 * @param attr The {@link AudioAttributes} whose volume index should be set.
1312 * @param index The volume index to set. See
1313 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1314 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1315 * @param flags One or more flags.
1316 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1317 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1318 * @see #isVolumeFixed()
1319 * @hide
1320 */
1321 @SystemApi
1322 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1323 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1324 Preconditions.checkNotNull(attr, "attr must not be null");
1325 final IAudioService service = getService();
1326 try {
1327 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001328 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001329 } catch (RemoteException e) {
1330 throw e.rethrowFromSystemServer();
1331 }
1332 }
1333
1334 /**
1335 * Returns the current volume index for a particular {@link AudioAttributes}.
1336 *
1337 * @param attr The {@link AudioAttributes} whose volume index is returned.
1338 * @return The current volume index for the stream.
1339 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1340 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1341 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1342 * @hide
1343 */
1344 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001345 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001346 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1347 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1348 Preconditions.checkNotNull(attr, "attr must not be null");
1349 final IAudioService service = getService();
1350 try {
1351 return service.getVolumeIndexForAttributes(attr);
1352 } catch (RemoteException e) {
1353 throw e.rethrowFromSystemServer();
1354 }
1355 }
1356
1357 /**
1358 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1359 *
1360 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1361 * @return The maximum valid volume index for the {@link AudioAttributes}.
1362 * @see #getVolumeIndexForAttributes(AudioAttributes)
1363 * @hide
1364 */
1365 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001366 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001367 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1368 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1369 Preconditions.checkNotNull(attr, "attr must not be null");
1370 final IAudioService service = getService();
1371 try {
1372 return service.getMaxVolumeIndexForAttributes(attr);
1373 } catch (RemoteException e) {
1374 throw e.rethrowFromSystemServer();
1375 }
1376 }
1377
1378 /**
1379 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1380 *
1381 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1382 * @return The minimum valid volume index for the {@link AudioAttributes}.
1383 * @see #getVolumeIndexForAttributes(AudioAttributes)
1384 * @hide
1385 */
1386 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001387 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001388 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1389 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1390 Preconditions.checkNotNull(attr, "attr must not be null");
1391 final IAudioService service = getService();
1392 try {
1393 return service.getMinVolumeIndexForAttributes(attr);
1394 } catch (RemoteException e) {
1395 throw e.rethrowFromSystemServer();
1396 }
1397 }
1398
1399 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001400 * Set the system usages to be supported on this device.
1401 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1402 * @hide
1403 */
1404 @SystemApi
1405 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1406 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1407 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1408 final IAudioService service = getService();
1409 try {
1410 service.setSupportedSystemUsages(systemUsages);
1411 } catch (RemoteException e) {
1412 throw e.rethrowFromSystemServer();
1413 }
1414 }
1415
1416 /**
1417 * Get the system usages supported on this device.
1418 * @return array of supported system usages {@link AttributeSystemUsage}
1419 * @hide
1420 */
1421 @SystemApi
1422 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1423 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1424 final IAudioService service = getService();
1425 try {
1426 return service.getSupportedSystemUsages();
1427 } catch (RemoteException e) {
1428 throw e.rethrowFromSystemServer();
1429 }
1430 }
1431
1432 /**
RoboErik4197cb62015-01-21 15:45:32 -08001433 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001435 * Do not use. This method has been deprecated and is now a no-op.
1436 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 *
1438 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001439 * @param state The required solo state: true for solo ON, false for solo
1440 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001441 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001442 * @deprecated Do not use. If you need exclusive audio playback use
1443 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 */
RoboErik4197cb62015-01-21 15:45:32 -08001445 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001447 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449
1450 /**
1451 * Mute or unmute an audio stream.
1452 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001453 * This method should only be used by applications that replace the
1454 * platform-wide management of audio settings or the main telephony
1455 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001457 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001458 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001459 * <p>
1460 * This method was deprecated in API level 22. Prior to API level 22 this
1461 * method had significantly different behavior and should be used carefully.
1462 * The following applies only to pre-22 platforms:
1463 * <ul>
1464 * <li>The mute command is protected against client process death: if a
1465 * process with an active mute request on a stream dies, this stream will be
1466 * unmuted automatically.</li>
1467 * <li>The mute requests for a given stream are cumulative: the AudioManager
1468 * can receive several mute requests from one or more clients and the stream
1469 * will be unmuted only when the same number of unmute requests are
1470 * received.</li>
1471 * <li>For a better user experience, applications MUST unmute a muted stream
1472 * in onPause() and mute is again in onResume() if appropriate.</li>
1473 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 *
1475 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001476 * @param state The required mute state: true for mute ON, false for mute
1477 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001478 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001479 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1480 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 */
RoboErik4197cb62015-01-21 15:45:32 -08001482 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001484 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1485 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1486 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1487 adjustSuggestedStreamVolume(direction, streamType, 0);
1488 } else {
1489 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 }
1491 }
1492
1493 /**
RoboErik4197cb62015-01-21 15:45:32 -08001494 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001495 *
RoboErik4197cb62015-01-21 15:45:32 -08001496 * @param streamType The stream to get mute state for.
1497 * @return The mute state for the given stream.
1498 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001499 */
1500 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001501 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001502 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001503 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001504 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001505 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001506 }
1507 }
1508
1509 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001510 * get master mute state.
1511 *
1512 * @hide
1513 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001514 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001515 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001516 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001517 try {
1518 return service.isMasterMute();
1519 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001520 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001521 }
1522 }
1523
1524 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001525 * forces the stream controlled by hard volume keys
1526 * specifying streamType == -1 releases control to the
1527 * logic.
1528 *
1529 * @hide
1530 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001531 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001532 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001533 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001534 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001535 try {
1536 service.forceVolumeControlStream(streamType, mICallBack);
1537 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001538 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001539 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001540 }
1541
1542 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 * Returns whether a particular type should vibrate according to user
1544 * settings and the current ringer mode.
1545 * <p>
1546 * This shouldn't be needed by most clients that use notifications to
1547 * vibrate. The notification manager will not vibrate if the policy doesn't
1548 * allow it, so the client should always set a vibrate pattern and let the
1549 * notification manager control whether or not to actually vibrate.
1550 *
1551 * @param vibrateType The type of vibrate. One of
1552 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1553 * {@link #VIBRATE_TYPE_RINGER}.
1554 * @return Whether the type should vibrate at the instant this method is
1555 * called.
1556 * @see #setVibrateSetting(int, int)
1557 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001558 * @deprecated Applications should maintain their own vibrate policy based on
1559 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 */
1561 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001562 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 try {
1564 return service.shouldVibrate(vibrateType);
1565 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001566 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
1568 }
1569
1570 /**
1571 * Returns whether the user's vibrate setting for a vibrate type.
1572 * <p>
1573 * This shouldn't be needed by most clients that want to vibrate, instead
1574 * see {@link #shouldVibrate(int)}.
1575 *
1576 * @param vibrateType The type of vibrate. One of
1577 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1578 * {@link #VIBRATE_TYPE_RINGER}.
1579 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1580 * {@link #VIBRATE_SETTING_OFF}, or
1581 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1582 * @see #setVibrateSetting(int, int)
1583 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001584 * @deprecated Applications should maintain their own vibrate policy based on
1585 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 */
1587 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001588 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 try {
1590 return service.getVibrateSetting(vibrateType);
1591 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001592 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 }
1594 }
1595
1596 /**
1597 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001598 * <p>
1599 * This method should only be used by applications that replace the platform-wide
1600 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 *
1602 * @param vibrateType The type of vibrate. One of
1603 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1604 * {@link #VIBRATE_TYPE_RINGER}.
1605 * @param vibrateSetting The vibrate setting, one of
1606 * {@link #VIBRATE_SETTING_ON},
1607 * {@link #VIBRATE_SETTING_OFF}, or
1608 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1609 * @see #getVibrateSetting(int)
1610 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001611 * @deprecated Applications should maintain their own vibrate policy based on
1612 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 */
1614 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001615 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 try {
1617 service.setVibrateSetting(vibrateType, vibrateSetting);
1618 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001619 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 }
1621 }
1622
1623 /**
1624 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001625 * <p>
1626 * This method should only be used by applications that replace the platform-wide
1627 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 *
1629 * @param on set <var>true</var> to turn on speakerphone;
1630 * <var>false</var> to turn it off
1631 */
1632 public void setSpeakerphoneOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001633 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001634 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001635 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001636 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001637 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 }
1640
1641 /**
1642 * Checks whether the speakerphone is on or off.
1643 *
1644 * @return true if speakerphone is on, false if it's off
1645 */
1646 public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001647 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001648 try {
1649 return service.isSpeakerphoneOn();
1650 } 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
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001655 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001656 * 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 -07001657 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001658 *
1659 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1660 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001661 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001662 * <ul>
1663 * <li> for each track independently, see
1664 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1665 * <li> application-wide at runtime, with this method </li>
1666 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1667 * manifest. </li>
1668 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001669 * The most restrictive policy is always applied.
1670 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001671 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001672 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001673 *
1674 * @param capturePolicy one of
1675 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1676 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1677 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001678 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001679 */
1680 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001681 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001682 final IAudioService service = getService();
1683 try {
1684 int result = service.setAllowedCapturePolicy(capturePolicy);
1685 if (result != AudioSystem.AUDIO_STATUS_OK) {
1686 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1687 return;
1688 }
1689 } catch (RemoteException e) {
1690 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001691 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001692 }
1693
Kevin Rocard019f60d2019-04-09 16:25:26 -07001694 /**
1695 * Return the capture policy.
1696 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1697 * the default if it was not called.
1698 */
1699 @AudioAttributes.CapturePolicy
1700 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001701 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1702 try {
1703 result = getService().getAllowedCapturePolicy();
1704 } catch (RemoteException e) {
1705 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1706 }
1707 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001708 }
1709
Eric Laurent3def1ee2010-03-17 23:26:26 -07001710 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001711 // Audio Product Strategy routing
1712
1713 /**
1714 * @hide
1715 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1716 * this audio strategy. Note that the device may not be available at the time the preferred
1717 * device is set, but it will be used once made available.
1718 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1719 * this preference for this strategy.</p>
1720 * @param strategy the audio strategy whose routing will be affected
1721 * @param device the audio device to route to when available
1722 * @return true if the operation was successful, false otherwise
1723 */
1724 @SystemApi
1725 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1726 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001727 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001728 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001729 }
1730
1731 /**
1732 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001733 * Removes the preferred audio device(s) previously set with
1734 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1735 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001736 * @param strategy the audio strategy whose routing will be affected
1737 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1738 * device set for example)
1739 */
1740 @SystemApi
1741 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1742 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1743 Objects.requireNonNull(strategy);
1744 try {
1745 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001746 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001747 return status == AudioSystem.SUCCESS;
1748 } catch (RemoteException e) {
1749 throw e.rethrowFromSystemServer();
1750 }
1751 }
1752
1753 /**
1754 * @hide
1755 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001756 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1757 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1758 * @param strategy the strategy to query
1759 * @return the preferred device for that strategy, if multiple devices are set as preferred
1760 * devices, the first one in the list will be returned. Null will be returned if none was
1761 * ever set or if the strategy is invalid
1762 */
1763 @SystemApi
1764 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1765 @Nullable
1766 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1767 @NonNull AudioProductStrategy strategy) {
1768 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1769 return devices.isEmpty() ? null : devices.get(0);
1770 }
1771
1772 /**
1773 * @hide
1774 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1775 * this audio strategy. Note that the devices may not be available at the time the preferred
1776 * devices is set, but it will be used once made available.
1777 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1778 * this preference for this strategy.</p>
1779 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1780 * devices used simultaneously to output the same audio signal.
1781 * @param strategy the audio strategy whose routing will be affected
1782 * @param devices a non-empty list of the audio devices to route to when available
1783 * @return true if the operation was successful, false otherwise
1784 */
1785 @SystemApi
1786 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1787 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1788 @NonNull List<AudioDeviceAttributes> devices) {
1789 Objects.requireNonNull(strategy);
1790 Objects.requireNonNull(devices);
1791 if (devices.isEmpty()) {
1792 throw new IllegalArgumentException(
1793 "Tried to set preferred devices for strategy with a empty list");
1794 }
1795 for (AudioDeviceAttributes device : devices) {
1796 Objects.requireNonNull(device);
1797 }
1798 try {
1799 final int status =
1800 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1801 return status == AudioSystem.SUCCESS;
1802 } catch (RemoteException e) {
1803 throw e.rethrowFromSystemServer();
1804 }
1805 }
1806
1807 /**
1808 * @hide
1809 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001810 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001811 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001812 * @param strategy the strategy to query
1813 * @return the preferred device for that strategy, or null if none was ever set or if the
1814 * strategy is invalid
1815 */
1816 @SystemApi
1817 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001818 @NonNull
1819 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001820 @NonNull AudioProductStrategy strategy) {
1821 Objects.requireNonNull(strategy);
1822 try {
jiabinf40141d2020-08-07 17:27:48 -07001823 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001824 } catch (RemoteException e) {
1825 throw e.rethrowFromSystemServer();
1826 }
1827 }
1828
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001829 /**
1830 * @hide
1831 * Interface to be notified of changes in the preferred audio device set for a given audio
1832 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001833 * <p>Note that this listener will only be invoked whenever
1834 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001835 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001836 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1837 * preferred device. It will not be invoked directly after registration with
1838 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1839 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001840 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001841 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1842 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001843 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001844 */
1845 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001846 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001847 public interface OnPreferredDeviceForStrategyChangedListener {
1848 /**
1849 * Called on the listener to indicate that the preferred audio device for the given
1850 * strategy has changed.
1851 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1852 * @param device <code>null</code> if the preferred device was removed, or the newly set
1853 * preferred audio device
1854 */
1855 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001856 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001857 }
1858
1859 /**
1860 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001861 * Interface to be notified of changes in the preferred audio devices set for a given audio
1862 * strategy.
1863 * <p>Note that this listener will only be invoked whenever
1864 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1865 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1866 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1867 * preferred device(s). It will not be invoked directly after registration with
1868 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1869 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1870 * to indicate which strategies had preferred devices at the time of registration.</p>
1871 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1872 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1873 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1874 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
1875 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1876 */
1877 @SystemApi
1878 public interface OnPreferredDevicesForStrategyChangedListener {
1879 /**
1880 * Called on the listener to indicate that the preferred audio devices for the given
1881 * strategy has changed.
1882 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1883 * @param devices a list of newly set preferred audio devices
1884 */
1885 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1886 @NonNull List<AudioDeviceAttributes> devices);
1887 }
1888
1889 /**
1890 * @hide
1891 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1892 * @param executor
1893 * @param listener
1894 * @throws SecurityException if the caller doesn't hold the required permission
1895 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1896 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1897 */
1898 @SystemApi
1899 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1900 @Deprecated
1901 public void addOnPreferredDeviceForStrategyChangedListener(
1902 @NonNull @CallbackExecutor Executor executor,
1903 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
1904 throws SecurityException {
1905 // No-op, the method is deprecated.
1906 }
1907
1908 /**
1909 * @hide
1910 * Removes a previously added listener of changes to the strategy-preferred audio device.
1911 * @param listener
1912 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
1913 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1914 */
1915 @SystemApi
1916 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1917 @Deprecated
1918 public void removeOnPreferredDeviceForStrategyChangedListener(
1919 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
1920 // No-op, the method is deprecated.
1921 }
1922
1923 /**
1924 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001925 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1926 * @param executor
1927 * @param listener
1928 * @throws SecurityException if the caller doesn't hold the required permission
1929 */
1930 @SystemApi
1931 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001932 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001933 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07001934 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001935 throws SecurityException {
1936 Objects.requireNonNull(executor);
1937 Objects.requireNonNull(listener);
1938 synchronized (mPrefDevListenerLock) {
1939 if (hasPrefDevListener(listener)) {
1940 throw new IllegalArgumentException(
jiabinf40141d2020-08-07 17:27:48 -07001941 "attempt to call addOnPreferredDevicesForStrategyChangedListener() "
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001942 + "on a previously registered listener");
1943 }
1944 // lazy initialization of the list of strategy-preferred device listener
1945 if (mPrefDevListeners == null) {
1946 mPrefDevListeners = new ArrayList<>();
1947 }
1948 final int oldCbCount = mPrefDevListeners.size();
1949 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor));
1950 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) {
1951 // register binder for callbacks
1952 if (mPrefDevDispatcherStub == null) {
jiabinf40141d2020-08-07 17:27:48 -07001953 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001954 }
1955 try {
jiabinf40141d2020-08-07 17:27:48 -07001956 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001957 } catch (RemoteException e) {
1958 throw e.rethrowFromSystemServer();
1959 }
1960 }
1961 }
1962 }
1963
1964 /**
1965 * @hide
1966 * Removes a previously added listener of changes to the strategy-preferred audio device.
1967 * @param listener
1968 */
1969 @SystemApi
1970 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001971 public void removeOnPreferredDevicesForStrategyChangedListener(
1972 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001973 Objects.requireNonNull(listener);
1974 synchronized (mPrefDevListenerLock) {
1975 if (!removePrefDevListener(listener)) {
1976 throw new IllegalArgumentException(
1977 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() "
1978 + "on an unregistered listener");
1979 }
1980 if (mPrefDevListeners.size() == 0) {
1981 // unregister binder for callbacks
1982 try {
jiabinf40141d2020-08-07 17:27:48 -07001983 getService().unregisterStrategyPreferredDevicesDispatcher(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001984 mPrefDevDispatcherStub);
1985 } catch (RemoteException e) {
1986 throw e.rethrowFromSystemServer();
1987 } finally {
1988 mPrefDevDispatcherStub = null;
1989 mPrefDevListeners = null;
1990 }
1991 }
1992 }
1993 }
1994
1995
1996 private final Object mPrefDevListenerLock = new Object();
1997 /**
1998 * List of listeners for preferred device for strategy and their associated Executor.
1999 * List is lazy-initialized on first registration
2000 */
2001 @GuardedBy("mPrefDevListenerLock")
2002 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners;
2003
2004 private static class PrefDevListenerInfo {
jiabinf40141d2020-08-07 17:27:48 -07002005 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002006 final @NonNull Executor mExecutor;
jiabinf40141d2020-08-07 17:27:48 -07002007 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002008 mListener = listener;
2009 mExecutor = exe;
2010 }
2011 }
2012
2013 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002014 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002015
jiabinf40141d2020-08-07 17:27:48 -07002016 private final class StrategyPreferredDevicesDispatcherStub
2017 extends IStrategyPreferredDevicesDispatcher.Stub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002018
2019 @Override
jiabinf40141d2020-08-07 17:27:48 -07002020 public void dispatchPrefDevicesChanged(int strategyId,
2021 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002022 // make a shallow copy of listeners so callback is not executed under lock
2023 final ArrayList<PrefDevListenerInfo> prefDevListeners;
2024 synchronized (mPrefDevListenerLock) {
2025 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) {
2026 return;
2027 }
2028 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone();
2029 }
2030 final AudioProductStrategy strategy =
2031 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2032 final long ident = Binder.clearCallingIdentity();
2033 try {
2034 for (PrefDevListenerInfo info : prefDevListeners) {
2035 info.mExecutor.execute(() ->
jiabinf40141d2020-08-07 17:27:48 -07002036 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices));
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002037 }
2038 } finally {
2039 Binder.restoreCallingIdentity(ident);
2040 }
2041 }
2042 }
2043
2044 @GuardedBy("mPrefDevListenerLock")
2045 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo(
jiabinf40141d2020-08-07 17:27:48 -07002046 OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002047 if (mPrefDevListeners == null) {
2048 return null;
2049 }
2050 for (PrefDevListenerInfo info : mPrefDevListeners) {
2051 if (info.mListener == listener) {
2052 return info;
2053 }
2054 }
2055 return null;
2056 }
2057
2058 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002059 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002060 return getPrefDevListenerInfo(listener) != null;
2061 }
2062
2063 @GuardedBy("mPrefDevListenerLock")
2064 /**
2065 * @return true if the listener was removed from the list
2066 */
jiabinf40141d2020-08-07 17:27:48 -07002067 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002068 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener);
2069 if (infoToRemove != null) {
2070 mPrefDevListeners.remove(infoToRemove);
2071 return true;
2072 }
2073 return false;
2074 }
2075
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002076 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002077 // Audio Capture Preset routing
2078
2079 /**
2080 * @hide
2081 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2082 * this capture preset. Note that the device may not be available at the time the preferred
2083 * device is set, but it will be used once made available.
2084 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2085 * for this capture preset.</p>
2086 * @param capturePreset the audio capture preset whose routing will be affected
2087 * @param device the audio device to route to when available
2088 * @return true if the operation was successful, false otherwise
2089 */
2090 @SystemApi
2091 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002092 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002093 @NonNull AudioDeviceAttributes device) {
2094 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2095 }
2096
2097 /**
2098 * @hide
2099 * Remove all the preferred audio devices previously set
2100 * @param capturePreset the audio capture preset whose routing will be affected
2101 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2102 * device set for example)
2103 */
2104 @SystemApi
2105 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002106 public boolean clearPreferredDevicesForCapturePreset(
2107 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002108 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2109 return false;
2110 }
2111 try {
2112 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2113 return status == AudioSystem.SUCCESS;
2114 } catch (RemoteException e) {
2115 throw e.rethrowFromSystemServer();
2116 }
2117 }
2118
2119 /**
2120 * @hide
2121 * Return the preferred devices for an audio capture preset, previously set with
2122 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2123 * @param capturePreset the capture preset to query
2124 * @return a list that contains preferred devices for that capture preset.
2125 */
2126 @NonNull
2127 @SystemApi
2128 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002129 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2130 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002131 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2132 return new ArrayList<AudioDeviceAttributes>();
2133 }
2134 try {
2135 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2136 } catch (RemoteException e) {
2137 throw e.rethrowFromSystemServer();
2138 }
2139 }
2140
2141 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002142 @MediaRecorder.SystemSource int capturePreset,
2143 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002144 Objects.requireNonNull(devices);
2145 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2146 return false;
2147 }
2148 if (devices.size() != 1) {
2149 throw new IllegalArgumentException(
2150 "Only support setting one preferred devices for capture preset");
2151 }
2152 for (AudioDeviceAttributes device : devices) {
2153 Objects.requireNonNull(device);
2154 }
2155 try {
2156 final int status =
2157 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2158 return status == AudioSystem.SUCCESS;
2159 } catch (RemoteException e) {
2160 throw e.rethrowFromSystemServer();
2161 }
2162 }
2163
2164 /**
2165 * @hide
2166 * Interface to be notified of changes in the preferred audio devices set for a given capture
2167 * preset.
2168 * <p>Note that this listener will only be invoked whenever
2169 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2170 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2171 * preferred device. It will not be invoked directly after registration with
2172 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2173 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2174 * to indicate which strategies had preferred devices at the time of registration.</p>
2175 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2176 * @see #clearPreferredDevicesForCapturePreset(int)
2177 * @see #getPreferredDevicesForCapturePreset(int)
2178 */
2179 @SystemApi
2180 public interface OnPreferredDevicesForCapturePresetChangedListener {
2181 /**
2182 * Called on the listener to indicate that the preferred audio devices for the given
2183 * capture preset has changed.
2184 * @param capturePreset the capture preset whose preferred device changed
2185 * @param devices a list of newly set preferred audio devices
2186 */
2187 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002188 @MediaRecorder.SystemSource int capturePreset,
2189 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002190 }
2191
2192 /**
2193 * @hide
2194 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2195 * @param executor
2196 * @param listener
2197 * @throws SecurityException if the caller doesn't hold the required permission
2198 */
2199 @SystemApi
2200 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2201 public void addOnPreferredDevicesForCapturePresetChangedListener(
2202 @NonNull @CallbackExecutor Executor executor,
2203 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2204 throws SecurityException {
2205 Objects.requireNonNull(executor);
2206 Objects.requireNonNull(listener);
2207 int status = addOnDevRoleForCapturePresetChangedListener(
2208 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2209 if (status == AudioSystem.ERROR) {
2210 // This must not happen
2211 throw new RuntimeException("Unknown error happened");
2212 }
2213 if (status == AudioSystem.BAD_VALUE) {
2214 throw new IllegalArgumentException(
2215 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2216 + "on a previously registered listener");
2217 }
2218 }
2219
2220 /**
2221 * @hide
2222 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2223 * @param listener
2224 */
2225 @SystemApi
2226 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2227 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2228 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2229 Objects.requireNonNull(listener);
2230 int status = removeOnDevRoleForCapturePresetChangedListener(
2231 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2232 if (status == AudioSystem.ERROR) {
2233 // This must not happen
2234 throw new RuntimeException("Unknown error happened");
2235 }
2236 if (status == AudioSystem.BAD_VALUE) {
2237 throw new IllegalArgumentException(
2238 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2239 + "on an unregistered listener");
2240 }
2241 }
2242
2243 private <T> int addOnDevRoleForCapturePresetChangedListener(
2244 @NonNull @CallbackExecutor Executor executor,
2245 @NonNull T listener, int deviceRole) {
2246 Objects.requireNonNull(executor);
2247 Objects.requireNonNull(listener);
2248 DevRoleListeners<T> devRoleListeners =
2249 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2250 if (devRoleListeners == null) {
2251 return AudioSystem.ERROR;
2252 }
2253 synchronized (devRoleListeners.mDevRoleListenersLock) {
2254 if (devRoleListeners.hasDevRoleListener(listener)) {
2255 return AudioSystem.BAD_VALUE;
2256 }
2257 // lazy initialization of the list of device role listener
2258 if (devRoleListeners.mListenerInfos == null) {
2259 devRoleListeners.mListenerInfos = new ArrayList<>();
2260 }
2261 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2262 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2263 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2264 // register binder for callbacks
2265 synchronized (mDevRoleForCapturePresetListenersLock) {
2266 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2267 mDeviceRoleListenersStatus |= (1 << deviceRole);
2268 if (deviceRoleListenerStatus != 0) {
2269 // There are already device role changed listeners active.
2270 return AudioSystem.SUCCESS;
2271 }
2272 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2273 mDevicesRoleForCapturePresetDispatcherStub =
2274 new CapturePresetDevicesRoleDispatcherStub();
2275 }
2276 try {
2277 getService().registerCapturePresetDevicesRoleDispatcher(
2278 mDevicesRoleForCapturePresetDispatcherStub);
2279 } catch (RemoteException e) {
2280 throw e.rethrowFromSystemServer();
2281 }
2282 }
2283 }
2284 }
2285 return AudioSystem.SUCCESS;
2286 }
2287
2288 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2289 @NonNull T listener, int deviceRole) {
2290 Objects.requireNonNull(listener);
2291 DevRoleListeners<T> devRoleListeners =
2292 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2293 if (devRoleListeners == null) {
2294 return AudioSystem.ERROR;
2295 }
2296 synchronized (devRoleListeners.mDevRoleListenersLock) {
2297 if (!devRoleListeners.removeDevRoleListener(listener)) {
2298 return AudioSystem.BAD_VALUE;
2299 }
2300 if (devRoleListeners.mListenerInfos.size() == 0) {
2301 // unregister binder for callbacks
2302 synchronized (mDevRoleForCapturePresetListenersLock) {
2303 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2304 if (mDeviceRoleListenersStatus != 0) {
2305 // There are some other device role changed listeners active.
2306 return AudioSystem.SUCCESS;
2307 }
2308 try {
2309 getService().unregisterCapturePresetDevicesRoleDispatcher(
2310 mDevicesRoleForCapturePresetDispatcherStub);
2311 } catch (RemoteException e) {
2312 throw e.rethrowFromSystemServer();
2313 }
2314 }
2315 }
2316 }
2317 return AudioSystem.SUCCESS;
2318 }
2319
2320 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
2321 put(AudioSystem.DEVICE_ROLE_PREFERRED,
2322 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
2323 }};
2324
2325 private class DevRoleListenerInfo<T> {
2326 final @NonNull Executor mExecutor;
2327 final @NonNull T mListener;
2328 DevRoleListenerInfo(Executor executor, T listener) {
2329 mExecutor = executor;
2330 mListener = listener;
2331 }
2332 }
2333
2334 private class DevRoleListeners<T> {
2335 private final Object mDevRoleListenersLock = new Object();
2336 @GuardedBy("mDevRoleListenersLock")
2337 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2338
2339 @GuardedBy("mDevRoleListenersLock")
2340 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2341 if (mListenerInfos == null) {
2342 return null;
2343 }
2344 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2345 if (listenerInfo.mListener == listener) {
2346 return listenerInfo;
2347 }
2348 }
2349 return null;
2350 }
2351
2352 @GuardedBy("mDevRoleListenersLock")
2353 private boolean hasDevRoleListener(T listener) {
2354 return getDevRoleListenerInfo(listener) != null;
2355 }
2356
2357 @GuardedBy("mDevRoleListenersLock")
2358 private boolean removeDevRoleListener(T listener) {
2359 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2360 if (infoToRemove != null) {
2361 mListenerInfos.remove(infoToRemove);
2362 return true;
2363 }
2364 return false;
2365 }
2366 }
2367
2368 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2369 /**
2370 * Record if there is a listener added for device role change. If there is a listener added for
2371 * a specified device role change, the bit at position `1 << device_role` is set.
2372 */
2373 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2374 private int mDeviceRoleListenersStatus = 0;
2375 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2376 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2377
2378 private final class CapturePresetDevicesRoleDispatcherStub
2379 extends ICapturePresetDevicesRoleDispatcher.Stub {
2380
2381 @Override
2382 public void dispatchDevicesRoleChanged(
2383 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2384 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2385 if (listenersObj == null) {
2386 return;
2387 }
2388 switch (role) {
2389 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2390 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2391 listeners =
2392 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2393 listenersObj;
2394 final ArrayList<DevRoleListenerInfo<
2395 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2396 synchronized (listeners.mDevRoleListenersLock) {
2397 if (listeners.mListenerInfos.isEmpty()) {
2398 return;
2399 }
2400 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2401 OnPreferredDevicesForCapturePresetChangedListener>>)
2402 listeners.mListenerInfos.clone();
2403 }
2404 final long ident = Binder.clearCallingIdentity();
2405 try {
2406 for (DevRoleListenerInfo<
2407 OnPreferredDevicesForCapturePresetChangedListener> info :
2408 prefDevListeners) {
2409 info.mExecutor.execute(() ->
2410 info.mListener.onPreferredDevicesForCapturePresetChanged(
2411 capturePreset, devices));
2412 }
2413 } finally {
2414 Binder.restoreCallingIdentity(ident);
2415 }
2416 } break;
2417 default:
2418 break;
2419 }
2420 }
2421 }
2422
2423 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002424 // Direct playback query
2425
2426 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2427 direct playback not supported. */
2428 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2429 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2430 direct offload playback supported. Compressed offload is a variant of direct playback.
2431 It is the feature that allows audio processing tasks to be done on the Android device but
2432 not on the application processor, instead, it is handled by dedicated hardware such as audio
2433 DSPs. That will allow the application processor to be idle as much as possible, which is
2434 good for power saving. Compressed offload playback supports
2435 {@link AudioTrack.StreamEventCallback} for event notifications. */
2436 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2437 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2438 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2439 direct offload playback supported with gapless transitions. Compressed offload is a variant
2440 of direct playback. It is the feature that allows audio processing tasks to be done on the
2441 Android device but not on the application processor, instead, it is handled by dedicated
2442 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2443 possible, which is good for power saving. Compressed offload playback supports
2444 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2445 indicates the ability to play consecutive audio tracks without an audio silence in
2446 between. */
2447 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2448 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2449 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2450 direct playback supported. This value covers direct playback that is bitstream pass-through
2451 such as compressed pass-through. */
2452 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2453 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2454
2455 /** @hide */
2456 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2457 DIRECT_PLAYBACK_NOT_SUPPORTED,
2458 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2459 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2460 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2461 )
2462 @Retention(RetentionPolicy.SOURCE)
2463 public @interface AudioDirectPlaybackMode {}
2464
2465 /**
2466 * Returns a bitfield representing the different forms of direct playback currently available
2467 * for a given audio format.
2468 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2469 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2470 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2471 * passthrough.
2472 * <p>Checking for direct support can help the app select the representation of audio content
2473 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2474 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2475 * streams, if needed.
2476 * @param format the audio format (codec, sample rate, channels) being checked.
2477 * @param attributes the {@link AudioAttributes} to be used for playback
2478 * @return the direct playback mode available with given format and attributes. The returned
2479 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2480 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2481 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2482 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2483 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2484 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2485 */
2486 @AudioDirectPlaybackMode
2487 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2488 @NonNull AudioAttributes attributes) {
2489 Objects.requireNonNull(format);
2490 Objects.requireNonNull(attributes);
2491 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2492 }
2493
2494 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002495 // Offload query
2496 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002497 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002498 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2499 * is not competing with other software resources. In general, it is supported by dedicated
2500 * hardware, such as audio DSPs.
2501 * <p>Note that this query only provides information about the support of an audio format,
2502 * it does not indicate whether the resources necessary for the offloaded playback are
2503 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002504 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002505 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002506 * @return true if the given audio format can be offloaded.
2507 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002508 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2509 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002510 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002511 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002512 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002513 if (attributes == null) {
2514 throw new NullPointerException("Illegal null AudioAttributes");
2515 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002516 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2517 }
2518
2519 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2520 offload playback not supported */
2521 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2522 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2523 offload playback supported */
2524 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2525 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2526 offload playback supported with gapless transitions */
2527 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2528 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2529
2530 /** @hide */
2531 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2532 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2533 PLAYBACK_OFFLOAD_SUPPORTED,
2534 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2535 )
2536 @Retention(RetentionPolicy.SOURCE)
2537 public @interface AudioOffloadMode {}
2538
2539 /**
2540 * Returns whether offloaded playback of an audio format is supported on the device or not and
2541 * when supported whether gapless transitions are possible or not.
2542 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2543 * is not competing with other software resources. In general, it is supported by dedicated
2544 * hardware, such as audio DSPs.
2545 * <p>Note that this query only provides information about the support of an audio format,
2546 * it does not indicate whether the resources necessary for the offloaded playback are
2547 * available at that instant.
2548 * @param format the audio format (codec, sample rate, channels) being checked.
2549 * @param attributes the {@link AudioAttributes} to be used for playback
2550 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2551 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2552 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2553 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002554 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002555 */
jiabine22f6aa2021-12-10 01:09:02 +00002556 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002557 @AudioOffloadMode
2558 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2559 @NonNull AudioAttributes attributes) {
2560 if (format == null) {
2561 throw new NullPointerException("Illegal null AudioFormat");
2562 }
2563 if (attributes == null) {
2564 throw new NullPointerException("Illegal null AudioAttributes");
2565 }
2566 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002567 }
2568
2569 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002570 // Immersive audio
2571
2572 /**
2573 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002574 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002575 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2576 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002577 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002578 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002579 return new Spatializer(this);
2580 }
2581
2582 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002583 // Bluetooth SCO control
2584 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002585 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002586 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002587 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2588 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2589 *
2590 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002591 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002592 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002593 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002594 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2595 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2596 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002597
2598 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002599 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002600 * connection state has been updated.
2601 * <p>This intent has two extras:
2602 * <ul>
2603 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2604 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2605 * </ul>
2606 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2607 * <ul>
2608 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2609 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2610 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2611 * </ul>
2612 * @see #startBluetoothSco()
2613 */
2614 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2615 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2616 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2617
Eric Laurent3def1ee2010-03-17 23:26:26 -07002618 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002619 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2620 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002621 */
2622 public static final String EXTRA_SCO_AUDIO_STATE =
2623 "android.media.extra.SCO_AUDIO_STATE";
2624
2625 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002626 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2627 * bluetooth SCO connection state.
2628 */
2629 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2630 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2631
2632 /**
2633 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2634 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002635 */
2636 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2637 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002638 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2639 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002640 */
2641 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2642 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002643 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2644 * indicating that the SCO audio channel is being established
2645 */
2646 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2647 /**
2648 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002649 * there was an error trying to obtain the state
2650 */
2651 public static final int SCO_AUDIO_STATE_ERROR = -1;
2652
2653
2654 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002655 * Indicates if current platform supports use of SCO for off call use cases.
2656 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002657 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002658 * feature.
2659 * @return true if bluetooth SCO can be used for audio when not in call
2660 * false otherwise
2661 * @see #startBluetoothSco()
2662 */
2663 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002664 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002665 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2666 }
2667
2668 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002669 * Start bluetooth SCO audio connection.
2670 * <p>Requires Permission:
2671 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2672 * <p>This method can be used by applications wanting to send and received audio
2673 * to/from a bluetooth SCO headset while the phone is not in call.
2674 * <p>As the SCO connection establishment can take several seconds,
2675 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002676 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002677 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002678 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2679 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2680 * registration. If the state is already CONNECTED, no state change will be received via the
2681 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2682 * so that the connection stays active in case the current initiator stops the connection.
2683 * <p>Unless the connection is already active as described above, the state will always
2684 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2685 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2686 * <p>When finished with the SCO connection or if the establishment fails, the application must
2687 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002688 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2689 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002690 * <ul>
2691 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2692 * <li> the format must be mono </li>
2693 * <li> the sampling must be 16kHz or 8kHz </li>
2694 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002695 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002696 * <ul>
2697 * <li> the format must be mono </li>
2698 * <li> the sampling must be 8kHz </li>
2699 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002700 * <p>Note that the phone application always has the priority on the usage of the SCO
2701 * connection for telephony. If this method is called while the phone is in call
2702 * it will be ignored. Similarly, if a call is received or sent while an application
2703 * is using the SCO connection, the connection will be lost for the application and NOT
2704 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002705 * <p>NOTE: up to and including API version
2706 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2707 * voice call to the bluetooth headset.
2708 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2709 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002710 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002711 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurent3def1ee2010-03-17 23:26:26 -07002712 */
2713 public void startBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002714 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002715 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002716 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002717 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002718 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002719 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002720 }
2721 }
2722
2723 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002724 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002725 * Start bluetooth SCO audio connection in virtual call mode.
2726 * <p>Requires Permission:
2727 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2728 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2729 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2730 * virtual call mode.
2731 * Applications using voice input for search or commands should first try raw audio connection
2732 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2733 * failure.
2734 * @see #startBluetoothSco()
2735 * @see #stopBluetoothSco()
2736 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2737 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002738 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002739 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002740 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002741 try {
2742 service.startBluetoothScoVirtualCall(mICallBack);
2743 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002744 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002745 }
2746 }
2747
2748 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002749 * Stop bluetooth SCO audio connection.
2750 * <p>Requires Permission:
2751 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2752 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002753 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2754 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002755 * @see #startBluetoothSco()
2756 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002757 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002758 public void stopBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002759 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002760 try {
2761 service.stopBluetoothSco(mICallBack);
2762 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002763 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002764 }
2765 }
2766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002768 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002769 * <p>
2770 * This method should only be used by applications that replace the platform-wide
2771 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002772 *
Eric Laurenta553c252009-07-17 12:17:14 -07002773 * @param on set <var>true</var> to use bluetooth SCO for communications;
2774 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 */
2776 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002777 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002778 try {
2779 service.setBluetoothScoOn(on);
2780 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002781 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 }
2784
2785 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002786 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002787 *
Eric Laurenta553c252009-07-17 12:17:14 -07002788 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 * false if otherwise
2790 */
2791 public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002792 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002793 try {
2794 return service.isBluetoothScoOn();
2795 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002796 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002798 }
2799
2800 /**
Eric Laurent242b3382012-06-15 11:48:50 -07002801 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2802 * headset; <var>false</var> disable A2DP audio
Eric Laurenta553c252009-07-17 12:17:14 -07002803 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002804 */
Eric Laurenta553c252009-07-17 12:17:14 -07002805 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002806 }
2807
2808 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002809 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002810 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002811 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002812 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002813 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 */
2815 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002816 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002817 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2818 return true;
2819 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2820 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2821 return true;
2822 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2823 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002824 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002825 }
Eric Laurent9656df22016-04-20 16:42:28 -07002826 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002827 }
2828
2829 /**
2830 * Sets audio routing to the wired headset on or off.
2831 *
2832 * @param on set <var>true</var> to route audio to/from wired
2833 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002834 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835 */
Eric Laurenta553c252009-07-17 12:17:14 -07002836 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002837 }
2838
2839 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002840 * Checks whether a wired headset is connected or not.
2841 * <p>This is not a valid indication that audio playback is
2842 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002844 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002846 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002847 */
2848 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002849 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002850 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002851 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002852 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2853 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2854 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002855 return false;
2856 } else {
2857 return true;
2858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002859 }
2860
2861 /**
2862 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002863 * <p>
2864 * This method should only be used by applications that replace the platform-wide
2865 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002866 *
2867 * @param on set <var>true</var> to mute the microphone;
2868 * <var>false</var> to turn mute off
2869 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002870 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002871 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002872 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002873 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002874 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002875 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002876 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002878 }
2879
2880 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002881 * @hide
2882 * Sets the microphone from switch mute on or off.
2883 * <p>
2884 * This method should only be used by InputManager to notify
2885 * Audio Subsystem about Microphone Mute switch state.
2886 *
2887 * @param on set <var>true</var> to mute the microphone;
2888 * <var>false</var> to turn mute off
2889 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002890 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002891 public void setMicrophoneMuteFromSwitch(boolean on) {
2892 final IAudioService service = getService();
2893 try {
2894 service.setMicrophoneMuteFromSwitch(on);
2895 } catch (RemoteException e) {
2896 throw e.rethrowFromSystemServer();
2897 }
2898 }
2899
2900 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002901 * Checks whether the microphone mute is on or off.
2902 *
2903 * @return true if microphone is muted, false if it's not
2904 */
2905 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002906 final IAudioService service = getService();
2907 try {
2908 return service.isMicrophoneMuted();
2909 } catch (RemoteException e) {
2910 throw e.rethrowFromSystemServer();
2911 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002912 }
2913
2914 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002915 * Broadcast Action: microphone muting state changed.
2916 *
2917 * You <em>cannot</em> receive this through components declared
2918 * in manifests, only by explicitly registering for it with
2919 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2920 * Context.registerReceiver()}.
2921 *
2922 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2923 * microphone is muted.
2924 */
2925 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2926 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2927 "android.media.action.MICROPHONE_MUTE_CHANGED";
2928
2929 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07002930 * Broadcast Action: speakerphone state changed.
2931 *
2932 * You <em>cannot</em> receive this through components declared
2933 * in manifests, only by explicitly registering for it with
2934 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2935 * Context.registerReceiver()}.
2936 *
2937 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2938 * speakerphone functionality is enabled or not.
2939 */
2940 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2941 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2942 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2943
2944 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002946 * <p>
2947 * The audio mode encompasses audio routing AND the behavior of
2948 * the telephony layer. Therefore this method should only be used by applications that
2949 * replace the platform-wide management of audio settings or the main telephony application.
2950 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2951 * application when it places a phone call, as it will cause signals from the radio layer
2952 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002954 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 * Informs the HAL about the current audio state so that
2956 * it can route the audio appropriately.
2957 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002958 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002959 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07002961 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002963 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 }
2965 }
2966
2967 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01002968 * This change id controls use of audio modes for call audio redirection.
2969 * @hide
2970 */
2971 @ChangeId
2972 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
2973 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
2974
2975 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 * Returns the current audio mode.
2977 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002978 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002980 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002982 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002984 int mode = service.getMode();
2985 int sdk;
2986 try {
2987 sdk = getContext().getApplicationInfo().targetSdkVersion;
2988 } catch (NullPointerException e) {
2989 // some tests don't have a Context
2990 sdk = Build.VERSION.SDK_INT;
2991 }
2992 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
2993 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01002994 } else if (mode == MODE_CALL_REDIRECT
2995 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
2996 mode = MODE_IN_CALL;
2997 } else if (mode == MODE_COMMUNICATION_REDIRECT
2998 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
2999 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003000 }
3001 return mode;
3002 } catch (RemoteException e) {
3003 throw e.rethrowFromSystemServer();
3004 }
3005 }
3006
3007 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003008 * Interface definition of a callback that is notified when the audio mode changes
3009 */
3010 public interface OnModeChangedListener {
3011 /**
3012 * Called on the listener to indicate that the audio mode has changed
3013 *
3014 * @param mode The current audio mode
3015 */
3016 void onModeChanged(@AudioMode int mode);
3017 }
3018
Nate Myren08635fe2021-04-20 12:04:39 -07003019 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003020 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003021 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003022 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3023 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003024
Nate Myren08635fe2021-04-20 12:04:39 -07003025
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003026 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3027 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003028
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003029 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003030 public void register(boolean register) {
3031 try {
3032 if (register) {
3033 getService().registerModeDispatcher(this);
3034 } else {
3035 getService().unregisterModeDispatcher(this);
3036 }
3037 } catch (RemoteException e) {
3038 e.rethrowFromSystemServer();
3039 }
3040 }
Nate Myren08635fe2021-04-20 12:04:39 -07003041
3042 @Override
3043 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003044 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003045 }
3046 }
3047
Nate Myren08635fe2021-04-20 12:04:39 -07003048 /**
3049 * Adds a listener to be notified of changes to the audio mode.
3050 * See {@link #getMode()}
3051 * @param executor
3052 * @param listener
3053 */
3054 public void addOnModeChangedListener(
3055 @NonNull @CallbackExecutor Executor executor,
3056 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003057 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3058 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003059 }
3060
3061 /**
3062 * Removes a previously added listener for changes to audio mode.
3063 * See {@link #getMode()}
3064 * @param listener
3065 */
3066 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003067 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003068 }
3069
3070 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003071 * Indicates if the platform supports a special call screening and call monitoring mode.
3072 * <p>
3073 * When this mode is supported, it is possible to perform call screening and monitoring
3074 * functions while other use cases like music or movie playback are active.
3075 * <p>
3076 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3077 * call screening mode.
3078 * <p>
3079 * If call screening mode is not supported, setting mode to
3080 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3081 * {@link #getMode()}.
3082 * @return true if call screening mode is supported, false otherwise.
3083 */
3084 public boolean isCallScreeningModeSupported() {
3085 final IAudioService service = getService();
3086 try {
3087 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003089 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 }
3091 }
3092
3093 /* modes for setMode/getMode/setRoute/getRoute */
3094 /**
3095 * Audio harware modes.
3096 */
3097 /**
3098 * Invalid audio mode.
3099 */
3100 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3101 /**
3102 * Current audio mode. Used to apply audio routing to current mode.
3103 */
3104 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3105 /**
3106 * Normal audio mode: not ringing and no call established.
3107 */
3108 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3109 /**
3110 * Ringing audio mode. An incoming is being signaled.
3111 */
3112 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3113 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003114 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115 */
3116 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003117 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003118 * In communication audio mode. An audio/video chat or VoIP call is established.
3119 */
3120 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003121 /**
3122 * Call screening in progress. Call is connected and audio is accessible to call
3123 * screening applications but other audio use cases are still possible.
3124 */
3125 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3126
Eric Laurent1c3408f2021-11-09 12:09:54 +01003127 /**
3128 * A telephony call is established and its audio is being redirected to another device.
3129 */
3130 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3131
3132 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003133 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003134 * device.
3135 */
3136 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3137
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003138 /** @hide */
3139 @IntDef(flag = false, prefix = "MODE_", value = {
3140 MODE_NORMAL,
3141 MODE_RINGTONE,
3142 MODE_IN_CALL,
3143 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003144 MODE_CALL_SCREENING,
3145 MODE_CALL_REDIRECT,
3146 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003147 )
3148 @Retention(RetentionPolicy.SOURCE)
3149 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150
3151 /* Routing bits for setRouting/getRouting API */
3152 /**
3153 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003154 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3155 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 */
Eric Laurenta553c252009-07-17 12:17:14 -07003157 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003159 * Routing audio output to speaker
3160 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3161 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 */
Eric Laurenta553c252009-07-17 12:17:14 -07003163 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 /**
3165 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003166 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3167 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 */
3169 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3170 /**
3171 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003172 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3173 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003174 */
Eric Laurenta553c252009-07-17 12:17:14 -07003175 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 /**
3177 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003178 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3179 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 */
Eric Laurenta553c252009-07-17 12:17:14 -07003181 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 /**
3183 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003184 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3185 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 */
Eric Laurenta553c252009-07-17 12:17:14 -07003187 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 /**
3189 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003190 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3191 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 */
Eric Laurenta553c252009-07-17 12:17:14 -07003193 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194
3195 /**
3196 * Sets the audio routing for a specified mode
3197 *
3198 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3199 * @param routes bit vector of routes requested, created from one or
3200 * more of ROUTE_xxx types. Set bits indicate that route should be on
3201 * @param mask bit vector of routes to change, created from one or more of
3202 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003203 *
3204 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003205 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 */
Eric Laurenta553c252009-07-17 12:17:14 -07003207 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209 }
3210
3211 /**
3212 * Returns the current audio routing bit vector for a specified mode.
3213 *
3214 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3215 * @return an audio route bit vector that can be compared with ROUTE_xxx
3216 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003217 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3218 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003220 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003221 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003222 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 }
3224
3225 /**
3226 * Checks whether any music is active.
3227 *
3228 * @return true if any music tracks are active.
3229 */
3230 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003231 final IAudioService service = getService();
3232 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003233 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003234 } catch (RemoteException e) {
3235 throw e.rethrowFromSystemServer();
3236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 }
3238
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003239 /**
3240 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003241 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3242 * display). Note that BT audio sinks are not considered remote devices.
3243 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3244 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003245 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003246 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003247 final IAudioService service = getService();
3248 try {
3249 return service.isMusicActive(true /*remotely*/);
3250 } catch (RemoteException e) {
3251 throw e.rethrowFromSystemServer();
3252 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003253 }
3254
3255 /**
3256 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003257 * Checks whether the current audio focus is exclusive.
3258 * @return true if the top of the audio focus stack requested focus
3259 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3260 */
3261 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003262 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003263 try {
3264 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3265 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003266 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003267 }
3268 }
3269
3270 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003271 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003272 * An audio session identifier is a system wide unique identifier for a set of audio streams
3273 * (one or more mixed together).
3274 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3275 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3276 * session ID will be applied to the mixed audio content of the players that share the same
3277 * audio session.
3278 * <p>This method can for instance be used when creating one of the
3279 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3280 * or to specify a session for a speech synthesis utterance
3281 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003282 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003283 * system failed to generate a new session, a condition in which audio playback or recording
3284 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003285 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003286 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003287 int session = AudioSystem.newAudioSessionId();
3288 if (session > 0) {
3289 return session;
3290 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003291 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003292 return ERROR;
3293 }
3294 }
3295
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003296 /**
3297 * A special audio session ID to indicate that the audio session ID isn't known and the
3298 * framework should generate a new value. This can be used when building a new
3299 * {@link AudioTrack} instance with
3300 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3301 */
3302 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3303
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305 /*
3306 * Sets a generic audio configuration parameter. The use of these parameters
3307 * are platform dependant, see libaudio
3308 *
3309 * ** Temporary interface - DO NOT USE
3310 *
3311 * TODO: Replace with a more generic key:value get/set mechanism
3312 *
3313 * param key name of parameter to set. Must not be null.
3314 * param value value of parameter. Must not be null.
3315 */
3316 /**
3317 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003318 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 */
Eric Laurenta553c252009-07-17 12:17:14 -07003320 @Deprecated public void setParameter(String key, String value) {
3321 setParameters(key+"="+value);
3322 }
3323
3324 /**
3325 * Sets a variable number of parameter values to audio hardware.
3326 *
3327 * @param keyValuePairs list of parameters key value pairs in the form:
3328 * key1=value1;key2=value2;...
3329 *
3330 */
3331 public void setParameters(String keyValuePairs) {
3332 AudioSystem.setParameters(keyValuePairs);
3333 }
3334
3335 /**
William Escandeef429b62021-10-15 18:37:40 +02003336 * @hide
3337 */
3338 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3339 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3340 public void setHfpEnabled(boolean enable) {
3341 AudioSystem.setParameters("hfp_enable=" + enable);
3342 }
3343
3344 /**
3345 * @hide
3346 */
3347 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3348 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3349 public void setHfpVolume(int volume) {
3350 AudioSystem.setParameters("hfp_volume=" + volume);
3351 }
3352
3353 /**
3354 * @hide
3355 */
3356 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3357 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3358 public void setHfpSamplingRate(int rate) {
3359 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3360 }
3361
3362 /**
3363 * @hide
3364 */
3365 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3366 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3367 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3368 boolean hasWbsEnabled) {
3369 AudioSystem.setParameters("bt_headset_name=" + name
3370 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3371 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3372 }
3373
3374 /**
3375 * @hide
3376 */
3377 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3378 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3379 public void setA2dpSuspended(boolean enable) {
3380 AudioSystem.setParameters("A2dpSuspended=" + enable);
3381 }
3382
3383 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003384 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003385 *
3386 * @param keys list of parameters
3387 * @return list of parameters key value pairs in the form:
3388 * key1=value1;key2=value2;...
3389 */
3390 public String getParameters(String keys) {
3391 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 }
3393
3394 /* Sound effect identifiers */
3395 /**
3396 * Keyboard and direction pad click sound
3397 * @see #playSoundEffect(int)
3398 */
3399 public static final int FX_KEY_CLICK = 0;
3400 /**
3401 * Focus has moved up
3402 * @see #playSoundEffect(int)
3403 */
3404 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3405 /**
3406 * Focus has moved down
3407 * @see #playSoundEffect(int)
3408 */
3409 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3410 /**
3411 * Focus has moved left
3412 * @see #playSoundEffect(int)
3413 */
3414 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3415 /**
3416 * Focus has moved right
3417 * @see #playSoundEffect(int)
3418 */
3419 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3420 /**
3421 * IME standard keypress sound
3422 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 */
3424 public static final int FX_KEYPRESS_STANDARD = 5;
3425 /**
3426 * IME spacebar keypress sound
3427 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 */
3429 public static final int FX_KEYPRESS_SPACEBAR = 6;
3430 /**
3431 * IME delete keypress sound
3432 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 */
3434 public static final int FX_KEYPRESS_DELETE = 7;
3435 /**
3436 * IME return_keypress sound
3437 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 */
3439 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003440
3441 /**
3442 * Invalid keypress sound
3443 * @see #playSoundEffect(int)
3444 */
3445 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003446
3447 /**
3448 * Back sound
3449 * @see #playSoundEffect(int)
3450 */
3451 public static final int FX_BACK = 10;
3452
3453 /**
3454 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003455 * <p>
3456 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3457 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003458 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3459 * @see #playSoundEffect(int)
3460 */
3461 public static final int FX_HOME = 11;
3462
3463 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003464 * @hide Navigation repeat sound 1
3465 * <p>
3466 * To be played by the framework when a focus navigation is repeatedly triggered
3467 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003468 * This is currently only used on TV devices.
3469 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3470 * @see #playSoundEffect(int)
3471 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003472 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003473
3474 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003475 * @hide Navigation repeat sound 2
3476 * <p>
3477 * To be played by the framework when a focus navigation is repeatedly triggered
3478 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003479 * This is currently only used on TV devices.
3480 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3481 * @see #playSoundEffect(int)
3482 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003483 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003484
3485 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003486 * @hide Navigation repeat sound 3
3487 * <p>
3488 * To be played by the framework when a focus navigation is repeatedly triggered
3489 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003490 * This is currently only used on TV devices.
3491 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3492 * @see #playSoundEffect(int)
3493 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003494 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003495
3496 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003497 * @hide Navigation repeat sound 4
3498 * <p>
3499 * To be played by the framework when a focus navigation is repeatedly triggered
3500 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003501 * This is currently only used on TV devices.
3502 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3503 * @see #playSoundEffect(int)
3504 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003505 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 /**
3508 * @hide Number of sound effects
3509 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003510 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003511 public static final int NUM_SOUND_EFFECTS = 16;
3512
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003513 /** @hide */
3514 @IntDef(prefix = { "FX_" }, value = {
3515 FX_KEY_CLICK,
3516 FX_FOCUS_NAVIGATION_UP,
3517 FX_FOCUS_NAVIGATION_DOWN,
3518 FX_FOCUS_NAVIGATION_LEFT,
3519 FX_FOCUS_NAVIGATION_RIGHT,
3520 FX_KEYPRESS_STANDARD,
3521 FX_KEYPRESS_SPACEBAR,
3522 FX_KEYPRESS_DELETE,
3523 FX_KEYPRESS_RETURN,
3524 FX_KEYPRESS_INVALID,
3525 FX_BACK
3526 })
3527 @Retention(RetentionPolicy.SOURCE)
3528 public @interface SystemSoundEffect {}
3529
Philip Junker7f1fdff2020-12-03 16:10:41 +01003530 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003531 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003532 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003533 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003534
3535 /**
3536 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003537 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3538 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003539 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003540 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003541 switch (n) {
3542 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003543 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003544 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003545 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003546 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003547 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003548 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003549 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003550 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003551 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003552 return -1;
3553 }
3554 }
3555
3556 /**
3557 * @hide
3558 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003559 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003560 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003561 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003562 } catch (RemoteException e) {
3563
3564 }
3565 }
3566
3567 /**
3568 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003569 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003570 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003571 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003572 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003573 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003574 } catch (RemoteException e) {
3575 throw e.rethrowFromSystemServer();
3576 }
3577 }
3578
3579 /**
3580 * @hide
3581 * @param enabled
3582 */
3583 public void setHomeSoundEffectEnabled(boolean enabled) {
3584 try {
3585 getService().setHomeSoundEffectEnabled(enabled);
3586 } catch (RemoteException e) {
3587
3588 }
3589 }
3590
3591 /**
3592 * @hide
3593 * @return true if the home sound effect is enabled
3594 */
3595 public boolean isHomeSoundEffectEnabled() {
3596 try {
3597 return getService().isHomeSoundEffectEnabled();
3598 } catch (RemoteException e) {
3599 throw e.rethrowFromSystemServer();
3600 }
3601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003602
3603 /**
3604 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003605 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 * NOTE: This version uses the UI settings to determine
3607 * whether sounds are heard or not.
3608 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003609 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003610 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003611 }
3612
3613 /**
3614 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003615 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003616 * @param userId The current user to pull sound settings from
3617 * NOTE: This version uses the UI settings to determine
3618 * whether sounds are heard or not.
3619 * @hide
3620 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003621 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003622 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3623 return;
3624 }
3625
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003626 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003627 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003628 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003629 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003630 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003631 }
3632 }
3633
3634 /**
3635 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003636 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003637 * @param volume Sound effect volume.
3638 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3639 * 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 -08003640 * NOTE: This version is for applications that have their own
3641 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003642 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003643 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3645 return;
3646 }
3647
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003648 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003649 try {
3650 service.playSoundEffectVolume(effectType, volume);
3651 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003652 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 }
3654 }
3655
3656 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003657 * Load Sound effects.
3658 * This method must be called when sound effects are enabled.
3659 */
3660 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003661 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003662 try {
3663 service.loadSoundEffects();
3664 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003665 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003666 }
3667 }
3668
3669 /**
3670 * Unload Sound effects.
3671 * This method can be called to free some memory when
3672 * sound effects are disabled.
3673 */
3674 public void unloadSoundEffects() {
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.unloadSoundEffects();
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
Eric Laurent4050c932009-07-08 02:52:14 -07003683 /**
Andy Hung69836952020-03-26 01:00:15 -07003684 * @hide
3685 */
3686 public static String audioFocusToString(int focus) {
3687 switch (focus) {
3688 case AUDIOFOCUS_NONE:
3689 return "AUDIOFOCUS_NONE";
3690 case AUDIOFOCUS_GAIN:
3691 return "AUDIOFOCUS_GAIN";
3692 case AUDIOFOCUS_GAIN_TRANSIENT:
3693 return "AUDIOFOCUS_GAIN_TRANSIENT";
3694 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3695 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3696 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3697 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3698 case AUDIOFOCUS_LOSS:
3699 return "AUDIOFOCUS_LOSS";
3700 case AUDIOFOCUS_LOSS_TRANSIENT:
3701 return "AUDIOFOCUS_LOSS_TRANSIENT";
3702 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3703 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3704 default:
3705 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3706 }
3707 }
3708
3709 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003710 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003711 */
3712 public static final int AUDIOFOCUS_NONE = 0;
3713
3714 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003715 * 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 -07003716 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003717 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003718 */
3719 public static final int AUDIOFOCUS_GAIN = 1;
3720 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003721 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3722 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3723 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003724 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003725 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003726 */
3727 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003728 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003729 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003730 * amount of time, and where it is acceptable for other audio applications to keep playing
3731 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003732 * Examples of temporary changes are the playback of driving directions where playback of music
3733 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003734 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003735 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3736 */
3737 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3738 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003739 * Used to indicate a temporary request of audio focus, anticipated to last a short
3740 * amount of time, during which no other applications, or system components, should play
3741 * anything. Examples of exclusive and transient audio focus requests are voice
3742 * memo recording and speech recognition, during which the system shouldn't play any
3743 * notifications, and media playback should have paused.
3744 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3745 */
3746 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3747 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003748 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003749 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003750 */
3751 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3752 /**
3753 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003754 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003755 */
3756 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3757 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003758 * 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 -07003759 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3760 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003761 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003762 */
3763 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3764 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003765
3766 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003767 * Interface definition for a callback to be invoked when the audio focus of the system is
3768 * updated.
3769 */
3770 public interface OnAudioFocusChangeListener {
3771 /**
3772 * Called on the listener to notify it the audio focus for this listener has been changed.
3773 * The focusChange value indicates whether the focus was gained,
3774 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3775 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003776 * When losing focus, listeners can use the focus change information to decide what
3777 * behavior to adopt when losing focus. A music player could for instance elect to lower
3778 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3779 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003780 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003781 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003782 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003783 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003784 }
3785
3786 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003787 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3788 */
3789 private static class FocusRequestInfo {
3790 @NonNull final AudioFocusRequest mRequest;
3791 @Nullable final Handler mHandler;
3792 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3793 mRequest = afr;
3794 mHandler = handler;
3795 }
3796 }
3797
3798 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003799 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3800 * to actual listener objects.
3801 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003802 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003803 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3804 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003805
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003806 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003807 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003808 }
3809
3810 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003811 * Handler for events (audio focus change, recording config change) coming from the
3812 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003813 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003814 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003815 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003816
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003817 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003818 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003819 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003820 private final static int MSSG_FOCUS_CHANGE = 0;
3821 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003822 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003823
3824 /**
3825 * Helper class to handle the forwarding of audio service events to the appropriate listener
3826 */
3827 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003828 private final Handler mHandler;
3829
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003830 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003831 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003832 if (handler == null) {
3833 if ((looper = Looper.myLooper()) == null) {
3834 looper = Looper.getMainLooper();
3835 }
3836 } else {
3837 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003838 }
3839
3840 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003841 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003842 mHandler = new Handler(looper) {
3843 @Override
3844 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003845 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003846 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003847 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3848 if (fri != null) {
3849 final OnAudioFocusChangeListener listener =
3850 fri.mRequest.getOnAudioFocusChangeListener();
3851 if (listener != null) {
3852 Log.d(TAG, "dispatching onAudioFocusChange("
3853 + msg.arg1 + ") to " + msg.obj);
3854 listener.onAudioFocusChange(msg.arg1);
3855 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003856 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003857 } break;
3858 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08003859 final RecordConfigChangeCallbackData cbData =
3860 (RecordConfigChangeCallbackData) msg.obj;
3861 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07003862 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08003863 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003864 } break;
3865 case MSSG_PLAYBACK_CONFIG_CHANGE: {
3866 final PlaybackConfigChangeCallbackData cbData =
3867 (PlaybackConfigChangeCallbackData) msg.obj;
3868 if (cbData.mCb != null) {
3869 if (DEBUG) {
3870 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3871 }
3872 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3873 }
3874 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003875 default:
3876 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003877 }
3878 }
3879 };
3880 } else {
3881 mHandler = null;
3882 }
3883 }
3884
3885 Handler getHandler() {
3886 return mHandler;
3887 }
3888 }
3889
Glenn Kasten30c918c2011-11-10 17:56:41 -08003890 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003891 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003892 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003893 final FocusRequestInfo fri = findFocusRequestInfo(id);
3894 if (fri != null) {
3895 final OnAudioFocusChangeListener listener =
3896 fri.mRequest.getOnAudioFocusChangeListener();
3897 if (listener != null) {
3898 final Handler h = (fri.mHandler == null) ?
3899 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3900 final Message m = h.obtainMessage(
3901 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3902 id/*obj*/);
3903 h.sendMessage(m);
3904 }
3905 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003906 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003907
3908 @Override
3909 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3910 synchronized (mFocusRequestsLock) {
3911 // TODO use generation counter as the key instead
3912 final BlockingFocusResultReceiver focusReceiver =
3913 mFocusRequestsAwaitingResult.remove(clientId);
3914 if (focusReceiver != null) {
3915 focusReceiver.notifyResult(requestResult);
3916 } else {
3917 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3918 }
3919 }
3920 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003921 };
3922
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003923 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003924 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07003925 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003926 } else {
3927 return new String(this.toString() + l.toString());
3928 }
3929 }
3930
3931 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003932 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003933 * Registers a listener to be called when audio focus changes and keeps track of the associated
3934 * focus request (including Handler to use for the listener).
3935 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003936 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003937 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3938 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3939 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3940 new ServiceEventHandlerDelegate(h).getHandler());
3941 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3942 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003943 }
3944
3945 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003946 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003947 * Causes the specified listener to not be called anymore when focus is gained or lost.
3948 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003949 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003950 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003951 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003952 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003953 }
3954
3955
3956 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003957 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003958 */
3959 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3960 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003961 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003962 */
3963 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003964 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003965 * A focus change request whose granting is delayed: the request was successful, but the
3966 * requester will only be granted audio focus once the condition that prevented immediate
3967 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003968 * See {@link #requestAudioFocus(AudioFocusRequest)} and
3969 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003970 */
3971 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003972
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003973 /** @hide */
3974 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3975 AUDIOFOCUS_REQUEST_FAILED,
3976 AUDIOFOCUS_REQUEST_GRANTED,
3977 AUDIOFOCUS_REQUEST_DELAYED }
3978 )
3979 @Retention(RetentionPolicy.SOURCE)
3980 public @interface FocusRequestResult {}
3981
3982 /**
3983 * @hide
3984 * code returned when a synchronous focus request on the client-side is to be blocked
3985 * until the external audio focus policy decides on the response for the client
3986 */
3987 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
3988
3989 /**
3990 * Timeout duration in ms when waiting on an external focus policy for the result for a
3991 * focus request
3992 */
3993 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
3994
3995 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
3996
3997 private final Object mFocusRequestsLock = new Object();
3998 /**
3999 * Map of all receivers of focus request results, one per unresolved focus request.
4000 * Receivers are added before sending the request to the external focus policy,
4001 * and are removed either after receiving the result, or after the timeout.
4002 * This variable is lazily initialized.
4003 */
4004 @GuardedBy("mFocusRequestsLock")
4005 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4006
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004007
4008 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004009 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004010 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004011 * @param l the listener to be notified of audio focus changes
4012 * @param streamType the main audio stream type affected by the focus request
4013 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4014 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004015 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004016 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4017 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004018 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4019 * that benefits from the system not playing disruptive sounds like notifications, for
4020 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004021 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004022 * as the playback of a song or a video.
4023 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004024 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004025 */
4026 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004027 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4028 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004029 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004030
4031 try {
4032 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4033 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4034 // AUDIOFOCUS_FLAG_DELAY_OK flag
4035 status = requestAudioFocus(l,
4036 new AudioAttributes.Builder()
4037 .setInternalLegacyStreamType(streamType).build(),
4038 durationHint,
4039 0 /* flags, legacy behavior */);
4040 } catch (IllegalArgumentException e) {
4041 Log.e(TAG, "Audio focus request denied due to ", e);
4042 }
4043
4044 return status;
4045 }
4046
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004047 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004048 /**
4049 * @hide
4050 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4051 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4052 * the system is in a state where focus cannot change, but be granted focus later when
4053 * this condition ends.
4054 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004055 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004056 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004057 /**
4058 * @hide
4059 * Use this flag when requesting audio focus to indicate that the requester
4060 * will pause its media playback (if applicable) when losing audio focus with
4061 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4062 * <br>On some platforms, the ducking may be handled without the application being aware of it
4063 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4064 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4065 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4066 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004067 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004068 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4069 /**
4070 * @hide
4071 * Use this flag to lock audio focus so granting is temporarily disabled.
4072 * <br>This flag can only be used by owners of a registered
4073 * {@link android.media.audiopolicy.AudioPolicy} in
4074 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4075 */
4076 @SystemApi
4077 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004078
4079 /**
4080 * @hide
4081 * flag set on test API calls,
4082 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004083 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004084 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004085 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004086 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4087 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004088 /** @hide */
4089 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004090 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004091
4092 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004093 * Request audio focus.
4094 * See the {@link AudioFocusRequest} for information about the options available to configure
4095 * your request, and notification of focus gain and loss.
4096 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4097 * requested.
4098 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4099 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4100 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4101 * is requested without building the {@link AudioFocusRequest} with
4102 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4103 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004104 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004105 */
4106 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004107 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004108 }
4109
4110 /**
4111 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4112 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4113 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4114 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4115 * @throws IllegalArgumentException if passed a null argument
4116 */
4117 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4118 if (focusRequest == null) {
4119 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4120 }
4121 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4122 focusRequest.getAudioAttributes());
4123 }
4124
4125 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004126 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004127 * Request audio focus.
4128 * Send a request to obtain the audio focus. This method differs from
4129 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4130 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004131 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4132 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4133 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4134 * requesting audio focus.
4135 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4136 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4137 * for the playback of driving directions, or notifications sounds.
4138 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4139 * the previous focus owner to keep playing if it ducks its audio output.
4140 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4141 * that benefits from the system not playing disruptive sounds like notifications, for
4142 * usecases such as voice memo recording, or speech recognition.
4143 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4144 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004145 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4146 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004147 * <br>Use 0 when not using any flags for the request, which behaves like
4148 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4149 * focus is granted immediately, or the grant request fails because the system is in a
4150 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004151 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4152 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4153 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4154 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4155 * @throws IllegalArgumentException
4156 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004157 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004158 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004159 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004160 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004161 int durationHint,
4162 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004163 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4164 throw new IllegalArgumentException("Invalid flags 0x"
4165 + Integer.toHexString(flags).toUpperCase());
4166 }
4167 return requestAudioFocus(l, requestAttributes, durationHint,
4168 flags & AUDIOFOCUS_FLAGS_APPS,
4169 null /* no AudioPolicy*/);
4170 }
4171
4172 /**
4173 * @hide
4174 * Request or lock audio focus.
4175 * This method is to be used by system components that have registered an
4176 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4177 * so focus granting is temporarily disabled.
4178 * @param l see the description of the same parameter in
4179 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4180 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4181 * requesting audio focus.
4182 * @param durationHint see the description of the same parameter in
4183 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4184 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004185 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004186 * <br>Use 0 when not using any flags for the request, which behaves like
4187 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4188 * focus is granted immediately, or the grant request fails because the system is in a
4189 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004190 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4191 * focus, or null.
4192 * @return see the description of the same return value in
4193 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4194 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004195 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004196 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004197 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004198 @RequiresPermission(anyOf= {
4199 android.Manifest.permission.MODIFY_PHONE_STATE,
4200 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4201 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004202 public int requestAudioFocus(OnAudioFocusChangeListener l,
4203 @NonNull AudioAttributes requestAttributes,
4204 int durationHint,
4205 int flags,
4206 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004207 // parameter checking
4208 if (requestAttributes == null) {
4209 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4210 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004211 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004212 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004213 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004214 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004215 throw new IllegalArgumentException("Illegal flags 0x"
4216 + Integer.toHexString(flags).toUpperCase());
4217 }
4218 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4219 throw new IllegalArgumentException(
4220 "Illegal null focus listener when flagged as accepting delayed focus grant");
4221 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004222 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4223 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4224 throw new IllegalArgumentException(
4225 "Illegal null focus listener when flagged as pausing instead of ducking");
4226 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004227 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4228 throw new IllegalArgumentException(
4229 "Illegal null audio policy when locking audio focus");
4230 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004231
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004232 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004233 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004234 .setAudioAttributes(requestAttributes)
4235 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4236 == AUDIOFOCUS_FLAG_DELAY_OK)
4237 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4238 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4239 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4240 .build();
4241 return requestAudioFocus(afr, ap);
4242 }
4243
4244 /**
4245 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004246 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4247 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4248 * @param afr the parameters of the request
4249 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4250 * @param clientFakeUid the UID of the client, here an arbitrary int,
4251 * doesn't have to be a real UID
4252 * @param clientTargetSdk the target SDK used by the client
4253 * @return return code indicating status of the request
4254 */
4255 @TestApi
4256 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4257 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4258 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4259 Objects.requireNonNull(afr);
4260 Objects.requireNonNull(clientFakeId);
4261 try {
4262 return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4263 afr.getFocusGain(),
4264 mICallBack,
4265 mAudioFocusDispatcher,
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004266 clientFakeId, "com.android.test.fakeclient",
4267 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4268 clientFakeUid, clientTargetSdk);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004269 } catch (RemoteException e) {
4270 throw e.rethrowFromSystemServer();
4271 }
4272 }
4273
4274 /**
4275 * @hide
4276 * Test API to abandon audio focus for an arbitrary client.
4277 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4278 * @param afr the parameters used for the request
4279 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4280 * would be requesting
4281 * @return return code indicating status of the request
4282 */
4283 @TestApi
4284 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4285 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4286 @NonNull String clientFakeId) {
4287 Objects.requireNonNull(afr);
4288 Objects.requireNonNull(clientFakeId);
4289 try {
4290 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4291 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4292 } catch (RemoteException e) {
4293 throw e.rethrowFromSystemServer();
4294 }
4295 }
4296
4297 /**
4298 * @hide
4299 * Return the duration of the fade out applied when a player of the given AudioAttributes
4300 * is losing audio focus
4301 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4302 * @return a duration in ms, 0 indicates no fade out is applied
4303 */
4304 @TestApi
4305 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4306 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4307 {
4308 Objects.requireNonNull(aa);
4309 try {
4310 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4311 } catch (RemoteException e) {
4312 throw e.rethrowFromSystemServer();
4313 }
4314 }
4315
4316 /**
4317 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004318 * Request or lock audio focus.
4319 * This method is to be used by system components that have registered an
4320 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4321 * so focus granting is temporarily disabled.
4322 * @param afr see the description of the same parameter in
4323 * {@link #requestAudioFocus(AudioFocusRequest)}
4324 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4325 * focus, or null.
4326 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4327 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4328 * @throws NullPointerException if the AudioFocusRequest is null
4329 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4330 */
4331 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004332 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004333 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4334 if (afr == null) {
4335 throw new NullPointerException("Illegal null AudioFocusRequest");
4336 }
4337 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4338 if (afr.locksFocus() && ap == null) {
4339 throw new IllegalArgumentException(
4340 "Illegal null audio policy when locking audio focus");
4341 }
4342 registerAudioFocusRequest(afr);
4343 final IAudioService service = getService();
4344 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004345 int sdk;
4346 try {
4347 sdk = getContext().getApplicationInfo().targetSdkVersion;
4348 } catch (NullPointerException e) {
4349 // some tests don't have a Context
4350 sdk = Build.VERSION.SDK_INT;
4351 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004352
4353 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4354 final BlockingFocusResultReceiver focusReceiver;
4355 synchronized (mFocusRequestsLock) {
4356 try {
4357 // TODO status contains result and generation counter for ext policy
4358 status = service.requestAudioFocus(afr.getAudioAttributes(),
4359 afr.getFocusGain(), mICallBack,
4360 mAudioFocusDispatcher,
4361 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004362 getContext().getOpPackageName() /* package name */,
4363 getContext().getAttributionTag(),
4364 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004365 ap != null ? ap.cb() : null,
4366 sdk);
4367 } catch (RemoteException e) {
4368 throw e.rethrowFromSystemServer();
4369 }
4370 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4371 // default path with no external focus policy
4372 return status;
4373 }
4374 if (mFocusRequestsAwaitingResult == null) {
4375 mFocusRequestsAwaitingResult =
4376 new HashMap<String, BlockingFocusResultReceiver>(1);
4377 }
4378 focusReceiver = new BlockingFocusResultReceiver(clientId);
4379 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004380 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004381 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4382 if (DEBUG && !focusReceiver.receivedResult()) {
4383 Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4384 }
4385 synchronized (mFocusRequestsLock) {
4386 mFocusRequestsAwaitingResult.remove(clientId);
4387 }
4388 return focusReceiver.requestResult();
4389 }
4390
4391 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4392 private static final class SafeWaitObject {
4393 private boolean mQuit = false;
4394
4395 public void safeNotify() {
4396 synchronized (this) {
4397 mQuit = true;
4398 this.notify();
4399 }
4400 }
4401
4402 public void safeWait(long millis) throws InterruptedException {
4403 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4404 synchronized (this) {
4405 while (!mQuit) {
4406 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4407 if (timeToWait < 0) { break; }
4408 this.wait(timeToWait);
4409 }
4410 }
4411 }
4412 }
4413
4414 private static final class BlockingFocusResultReceiver {
4415 private final SafeWaitObject mLock = new SafeWaitObject();
4416 @GuardedBy("mLock")
4417 private boolean mResultReceived = false;
4418 // request denied by default (e.g. timeout)
4419 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4420 private final String mFocusClientId;
4421
4422 BlockingFocusResultReceiver(String clientId) {
4423 mFocusClientId = clientId;
4424 }
4425
4426 boolean receivedResult() { return mResultReceived; }
4427 int requestResult() { return mFocusRequestResult; }
4428
4429 void notifyResult(int requestResult) {
4430 synchronized (mLock) {
4431 mResultReceived = true;
4432 mFocusRequestResult = requestResult;
4433 mLock.safeNotify();
4434 }
4435 }
4436
4437 public void waitForResult(long timeOutMs) {
4438 synchronized (mLock) {
4439 if (mResultReceived) {
4440 // the result was received before waiting
4441 return;
4442 }
4443 try {
4444 mLock.safeWait(timeOutMs);
4445 } catch (InterruptedException e) { }
4446 }
4447 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004448 }
4449
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004450 /**
4451 * @hide
4452 * Used internally by telephony package to request audio focus. Will cause the focus request
4453 * to be associated with the "voice communication" identifier only used in AudioService
4454 * to identify this use case.
4455 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4456 * the establishment of the call
4457 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4458 * media applications resume after a call
4459 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004460 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004461 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004462 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004463 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004464 service.requestAudioFocus(new AudioAttributes.Builder()
4465 .setInternalLegacyStreamType(streamType).build(),
4466 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004467 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004468 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004469 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004470 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004471 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004472 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004473 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004474 }
4475 }
4476
4477 /**
4478 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004479 * Return the volume ramping time for a sound to be played after the given focus request,
4480 * and to play a sound of the given attributes
4481 * @param focusGain
4482 * @param attr
4483 * @return
4484 */
4485 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004486 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004487 try {
4488 return service.getFocusRampTimeMs(focusGain, attr);
4489 } catch (RemoteException e) {
4490 throw e.rethrowFromSystemServer();
4491 }
4492 }
4493
4494 /**
4495 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004496 * Set the result to the audio focus request received through
4497 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4498 * @param afi the information about the focus requester
4499 * @param requestResult the result to the focus request to be passed to the requester
4500 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4501 */
4502 @SystemApi
4503 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4504 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4505 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4506 if (afi == null) {
4507 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4508 }
4509 if (ap == null) {
4510 throw new IllegalArgumentException("Illegal null AudioPolicy");
4511 }
4512 final IAudioService service = getService();
4513 try {
4514 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4515 } catch (RemoteException e) {
4516 throw e.rethrowFromSystemServer();
4517 }
4518 }
4519
4520 /**
4521 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004522 * Notifies an application with a focus listener of gain or loss of audio focus.
4523 * This method can only be used by owners of an {@link AudioPolicy} configured with
4524 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4525 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4526 * that was received by the {@code AudioPolicy} through
4527 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4528 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4529 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4530 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4531 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4532 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4533 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4534 * <br>For the focus gain, the change type should be the same as the app requested.
4535 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4536 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4537 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4538 * if there was an error sending the request.
4539 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4540 */
4541 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004542 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004543 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4544 @NonNull AudioPolicy ap) {
4545 if (afi == null) {
4546 throw new NullPointerException("Illegal null AudioFocusInfo");
4547 }
4548 if (ap == null) {
4549 throw new NullPointerException("Illegal null AudioPolicy");
4550 }
4551 final IAudioService service = getService();
4552 try {
4553 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4554 } catch (RemoteException e) {
4555 throw e.rethrowFromSystemServer();
4556 }
4557 }
4558
4559 /**
4560 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004561 * Used internally by telephony package to abandon audio focus, typically after a call or
4562 * when ringing ends and the call is rejected or not answered.
4563 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4564 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004565 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004566 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004567 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004568 try {
John Spurlock61560172015-02-06 19:46:04 -05004569 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004570 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004571 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004572 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004573 }
4574 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004575
4576 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004577 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4578 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004579 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004580 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004581 */
4582 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004583 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4584 }
4585
4586 /**
4587 * @hide
4588 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4589 * @param l the listener with which focus was requested.
4590 * @param aa the {@link AudioAttributes} with which audio focus was requested
4591 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004592 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004593 */
4594 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004595 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4596 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004597 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004598 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004599 unregisterAudioFocusRequest(l);
4600 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004601 try {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004602 status = service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004603 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004604 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004605 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004606 }
4607 return status;
4608 }
4609
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004610 //====================================================================
4611 // Remote Control
4612 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004613 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004614 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4615 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004616 * in the application manifest. The package of the component must match that of
4617 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004618 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004619 */
RoboErikb214efb2014-07-24 13:20:30 -07004620 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004621 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004622 if (eventReceiver == null) {
4623 return;
4624 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004625 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004626 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4627 "receiver and context package names don't match");
4628 return;
4629 }
4630 // construct a PendingIntent for the media button and register it
4631 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4632 // the associated intent will be handled by the component being registered
4633 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004634 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004635 0/*requestCode, ignored*/, mediaButtonIntent,
4636 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004637 registerMediaButtonIntent(pi, eventReceiver);
4638 }
4639
4640 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004641 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4642 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4643 * the buttons to go to any PendingIntent. Note that you should only use this form if
4644 * you know you will continue running for the full time until unregistering the
4645 * PendingIntent.
4646 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004647 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4648 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4649 * media button that was pressed.
4650 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004651 */
RoboErikb214efb2014-07-24 13:20:30 -07004652 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004653 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4654 if (eventReceiver == null) {
4655 return;
4656 }
4657 registerMediaButtonIntent(eventReceiver, null);
4658 }
4659
4660 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004661 * @hide
4662 * no-op if (pi == null) or (eventReceiver == null)
4663 */
4664 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004665 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004666 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4667 return;
4668 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004669 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4670 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004671 }
4672
4673 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004674 * Unregister the receiver of MEDIA_BUTTON intents.
4675 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4676 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004677 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004678 */
RoboErikb214efb2014-07-24 13:20:30 -07004679 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004680 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004681 if (eventReceiver == null) {
4682 return;
4683 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004684 // construct a PendingIntent for the media button and unregister it
4685 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4686 // the associated intent will be handled by the component being registered
4687 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004688 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004689 0/*requestCode, ignored*/, mediaButtonIntent,
4690 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004691 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004692 }
4693
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004694 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004695 * Unregister the receiver of MEDIA_BUTTON intents.
4696 * @param eventReceiver same PendingIntent that was registed with
4697 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004698 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004699 */
RoboErikb214efb2014-07-24 13:20:30 -07004700 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004701 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4702 if (eventReceiver == null) {
4703 return;
4704 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004705 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004706 }
4707
4708 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004709 * @hide
4710 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004711 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004712 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004713 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004714 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004715
4716 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004717 * Registers the remote control client for providing information to display on the remote
4718 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004719 * @param rcClient The remote control client from which remote controls will receive
4720 * information to display.
4721 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004722 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004723 */
RoboErikb214efb2014-07-24 13:20:30 -07004724 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004725 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004726 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004727 return;
4728 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004729 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004730 }
4731
4732 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004733 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004734 * remote controls.
4735 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004736 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004737 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004738 */
RoboErikb214efb2014-07-24 13:20:30 -07004739 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004740 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004741 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004742 return;
4743 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004744 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004745 }
4746
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004747 /**
RoboErika66c40b2014-08-15 15:21:41 -07004748 * Registers a {@link RemoteController} instance for it to receive media
4749 * metadata updates and playback state information from applications using
4750 * {@link RemoteControlClient}, and control their playback.
4751 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004752 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004753 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004754 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004755 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004756 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004757 * @return true if the {@link RemoteController} was successfully registered,
4758 * false if an error occurred, due to an internal system error, or
4759 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004760 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004761 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4762 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004763 */
RoboErikb214efb2014-07-24 13:20:30 -07004764 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004765 public boolean registerRemoteController(RemoteController rctlr) {
4766 if (rctlr == null) {
4767 return false;
4768 }
RoboErik430fc482014-06-12 15:49:20 -07004769 rctlr.startListeningToSessions();
4770 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004771 }
4772
4773 /**
RoboErika66c40b2014-08-15 15:21:41 -07004774 * Unregisters a {@link RemoteController}, causing it to no longer receive
4775 * media metadata and playback state information, and no longer be capable
4776 * of controlling playback.
4777 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004778 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004779 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004780 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4781 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004782 */
RoboErikb214efb2014-07-24 13:20:30 -07004783 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004784 public void unregisterRemoteController(RemoteController rctlr) {
4785 if (rctlr == null) {
4786 return;
4787 }
RoboErik430fc482014-06-12 15:49:20 -07004788 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004789 }
4790
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004791
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004792 //====================================================================
4793 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004794 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004795 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004796 * Register the given {@link AudioPolicy}.
4797 * This call is synchronous and blocks until the registration process successfully completed
4798 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004799 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004800 * @return {@link #ERROR} if there was an error communicating with the registration service
4801 * or if the user doesn't have the required
4802 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4803 * {@link #SUCCESS} otherwise.
4804 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004805 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004806 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004807 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004808 return registerAudioPolicyStatic(policy);
4809 }
4810
4811 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004812 if (policy == null) {
4813 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4814 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004815 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004816 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004817 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004818 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07004819 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4820 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004821 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004822 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004823 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004824 } else {
4825 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004826 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004827 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004828 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004829 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004830 }
4831 return SUCCESS;
4832 }
4833
4834 /**
4835 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004836 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004837 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004838 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004839 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004840 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004841 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004842 unregisterAudioPolicyAsyncStatic(policy);
4843 }
4844
4845 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004846 if (policy == null) {
4847 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4848 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004849 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004850 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004851 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004852 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004853 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004854 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004855 }
4856 }
4857
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004858 /**
4859 * @hide
4860 * Unregisters an {@link AudioPolicy} synchronously.
4861 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4862 * associated with mixes of this policy.
4863 * @param policy the non-null {@link AudioPolicy} to unregister.
4864 */
4865 @SystemApi
4866 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4867 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4868 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4869 final IAudioService service = getService();
4870 try {
4871 policy.invalidateCaptorsAndInjectors();
4872 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004873 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004874 } catch (RemoteException e) {
4875 throw e.rethrowFromSystemServer();
4876 }
4877 }
4878
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07004879 /**
4880 * @hide
4881 * @return true if an AudioPolicy was previously registered
4882 */
4883 @TestApi
4884 public boolean hasRegisteredDynamicPolicy() {
4885 final IAudioService service = getService();
4886 try {
4887 return service.hasRegisteredDynamicPolicy();
4888 } catch (RemoteException e) {
4889 throw e.rethrowFromSystemServer();
4890 }
4891 }
4892
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004893 //====================================================================
4894 // Notification of playback activity & playback configuration
4895 /**
4896 * Interface for receiving update notifications about the playback activity on the system.
4897 * Extend this abstract class and register it with
4898 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4899 * to be notified.
4900 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4901 * configuration.
4902 * @see AudioPlaybackConfiguration
4903 */
4904 public static abstract class AudioPlaybackCallback {
4905 /**
4906 * Called whenever the playback activity and configuration has changed.
4907 * @param configs list containing the results of
4908 * {@link AudioManager#getActivePlaybackConfigurations()}.
4909 */
4910 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4911 }
4912
4913 private static class AudioPlaybackCallbackInfo {
4914 final AudioPlaybackCallback mCb;
4915 final Handler mHandler;
4916 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4917 mCb = cb;
4918 mHandler = handler;
4919 }
4920 }
4921
4922 private final static class PlaybackConfigChangeCallbackData {
4923 final AudioPlaybackCallback mCb;
4924 final List<AudioPlaybackConfiguration> mConfigs;
4925
4926 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4927 List<AudioPlaybackConfiguration> configs) {
4928 mCb = cb;
4929 mConfigs = configs;
4930 }
4931 }
4932
4933 /**
4934 * Register a callback to be notified of audio playback changes through
4935 * {@link AudioPlaybackCallback}
4936 * @param cb non-null callback to register
4937 * @param handler the {@link Handler} object for the thread on which to execute
4938 * the callback. If <code>null</code>, the {@link Handler} associated with the main
4939 * {@link Looper} will be used.
4940 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08004941 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4942 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004943 {
4944 if (cb == null) {
4945 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4946 }
4947
4948 synchronized(mPlaybackCallbackLock) {
4949 // lazy initialization of the list of playback callbacks
4950 if (mPlaybackCallbackList == null) {
4951 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4952 }
4953 final int oldCbCount = mPlaybackCallbackList.size();
4954 if (!hasPlaybackCallback_sync(cb)) {
4955 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4956 new ServiceEventHandlerDelegate(handler).getHandler()));
4957 final int newCbCount = mPlaybackCallbackList.size();
4958 if ((oldCbCount == 0) && (newCbCount > 0)) {
4959 // register binder for callbacks
4960 try {
4961 getService().registerPlaybackCallback(mPlayCb);
4962 } catch (RemoteException e) {
4963 throw e.rethrowFromSystemServer();
4964 }
4965 }
4966 } else {
4967 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4968 + "registered callback");
4969 }
4970 }
4971 }
4972
4973 /**
4974 * Unregister an audio playback callback previously registered with
4975 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4976 * @param cb non-null callback to unregister
4977 */
4978 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4979 if (cb == null) {
4980 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4981 }
4982 synchronized(mPlaybackCallbackLock) {
4983 if (mPlaybackCallbackList == null) {
4984 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4985 + " that was never registered");
4986 return;
4987 }
4988 final int oldCbCount = mPlaybackCallbackList.size();
4989 if (removePlaybackCallback_sync(cb)) {
4990 final int newCbCount = mPlaybackCallbackList.size();
4991 if ((oldCbCount > 0) && (newCbCount == 0)) {
4992 // unregister binder for callbacks
4993 try {
4994 getService().unregisterPlaybackCallback(mPlayCb);
4995 } catch (RemoteException e) {
4996 throw e.rethrowFromSystemServer();
4997 }
4998 }
4999 } else {
5000 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5001 + " already unregistered or never registered");
5002 }
5003 }
5004 }
5005
5006 /**
5007 * Returns the current active audio playback configurations of the device
5008 * @return a non-null list of playback configurations. An empty list indicates there is no
5009 * playback active when queried.
5010 * @see AudioPlaybackConfiguration
5011 */
5012 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5013 final IAudioService service = getService();
5014 try {
5015 return service.getActivePlaybackConfigurations();
5016 } catch (RemoteException e) {
5017 throw e.rethrowFromSystemServer();
5018 }
5019 }
5020
5021 /**
5022 * All operations on this list are sync'd on mPlaybackCallbackLock.
5023 * List is lazy-initialized in
5024 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5025 * List can be null.
5026 */
5027 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5028 private final Object mPlaybackCallbackLock = new Object();
5029
5030 /**
5031 * Must be called synchronized on mPlaybackCallbackLock
5032 */
5033 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5034 if (mPlaybackCallbackList != null) {
5035 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5036 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5037 return true;
5038 }
5039 }
5040 }
5041 return false;
5042 }
5043
5044 /**
5045 * Must be called synchronized on mPlaybackCallbackLock
5046 */
5047 private boolean removePlaybackCallback_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 mPlaybackCallbackList.remove(i);
5052 return true;
5053 }
5054 }
5055 }
5056 return false;
5057 }
5058
5059 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005060 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005061 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5062 boolean flush) {
5063 if (flush) {
5064 Binder.flushPendingCommands();
5065 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005066 synchronized(mPlaybackCallbackLock) {
5067 if (mPlaybackCallbackList != null) {
5068 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5069 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5070 if (arci.mHandler != null) {
5071 final Message m = arci.mHandler.obtainMessage(
5072 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5073 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5074 arci.mHandler.sendMessage(m);
5075 }
5076 }
5077 }
5078 }
5079 }
5080
5081 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005082
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005083 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005084 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005085 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005086 * Interface for receiving update notifications about the recording configuration. Extend
5087 * this abstract class and register it with
5088 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5089 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005090 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5091 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005092 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005093 */
5094 public static abstract class AudioRecordingCallback {
5095 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005096 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005097 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005098 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005099 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005100 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005101 }
5102
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005103 private static class AudioRecordingCallbackInfo {
5104 final AudioRecordingCallback mCb;
5105 final Handler mHandler;
5106 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5107 mCb = cb;
5108 mHandler = handler;
5109 }
5110 }
5111
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005112 private final static class RecordConfigChangeCallbackData {
5113 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005114 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005115
5116 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005117 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005118 mCb = cb;
5119 mConfigs = configs;
5120 }
5121 }
5122
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005123 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005124 * Register a callback to be notified of audio recording changes through
5125 * {@link AudioRecordingCallback}
5126 * @param cb non-null callback to register
5127 * @param handler the {@link Handler} object for the thread on which to execute
5128 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5129 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005130 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005131 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5132 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005133 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005134 if (cb == null) {
5135 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5136 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005137
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005138 synchronized(mRecordCallbackLock) {
5139 // lazy initialization of the list of recording callbacks
5140 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005141 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005142 }
5143 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005144 if (!hasRecordCallback_sync(cb)) {
5145 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5146 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005147 final int newCbCount = mRecordCallbackList.size();
5148 if ((oldCbCount == 0) && (newCbCount > 0)) {
5149 // register binder for callbacks
5150 final IAudioService service = getService();
5151 try {
5152 service.registerRecordingCallback(mRecCb);
5153 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005154 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005155 }
5156 }
5157 } else {
5158 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5159 + "registered callback");
5160 }
5161 }
5162 }
5163
5164 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005165 * Unregister an audio recording callback previously registered with
5166 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5167 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005168 */
5169 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5170 if (cb == null) {
5171 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5172 }
5173 synchronized(mRecordCallbackLock) {
5174 if (mRecordCallbackList == null) {
5175 return;
5176 }
5177 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005178 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005179 final int newCbCount = mRecordCallbackList.size();
5180 if ((oldCbCount > 0) && (newCbCount == 0)) {
5181 // unregister binder for callbacks
5182 final IAudioService service = getService();
5183 try {
5184 service.unregisterRecordingCallback(mRecCb);
5185 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005186 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005187 }
5188 }
5189 } else {
5190 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5191 + " already unregistered or never registered");
5192 }
5193 }
5194 }
5195
5196 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005197 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005198 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005199 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005200 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005201 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005202 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005203 final IAudioService service = getService();
5204 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005205 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005206 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005207 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005208 }
5209 }
5210
5211 /**
5212 * constants for the recording events, to keep in sync
5213 * with frameworks/av/include/media/AudioPolicy.h
5214 */
5215 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005216 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005217 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005218 public static final int RECORD_CONFIG_EVENT_START = 0;
5219 /** @hide */
5220 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5221 /** @hide */
5222 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5223 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005224 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005225 /**
5226 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5227 */
5228 /** @hide */
5229 public static final int RECORD_RIID_INVALID = -1;
5230 /** @hide */
5231 public static final int RECORDER_STATE_STARTED = 0;
5232 /** @hide */
5233 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005234
5235 /**
5236 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005237 * List is lazy-initialized in
5238 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005239 * List can be null.
5240 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005241 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005242 private final Object mRecordCallbackLock = new Object();
5243
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005244 /**
5245 * Must be called synchronized on mRecordCallbackLock
5246 */
5247 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5248 if (mRecordCallbackList != null) {
5249 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5250 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5251 return true;
5252 }
5253 }
5254 }
5255 return false;
5256 }
5257
5258 /**
5259 * Must be called synchronized on mRecordCallbackLock
5260 */
5261 private boolean removeRecordCallback_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 mRecordCallbackList.remove(i);
5266 return true;
5267 }
5268 }
5269 }
5270 return false;
5271 }
5272
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005273 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005274 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005275 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005276 synchronized(mRecordCallbackLock) {
5277 if (mRecordCallbackList != null) {
5278 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5279 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5280 if (arci.mHandler != null) {
5281 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005282 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5283 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005284 arci.mHandler.sendMessage(m);
5285 }
5286 }
5287 }
5288 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005289 }
5290
5291 };
5292
5293 //=====================================================================
5294
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005295 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005296 * @hide
5297 * Reload audio settings. This method is called by Settings backup
5298 * agent when audio settings are restored and causes the AudioService
5299 * to read and apply restored settings.
5300 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005301 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005302 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005303 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005304 try {
5305 service.reloadAudioSettings();
5306 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005307 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005308 }
5309 }
5310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005311 /**
5312 * {@hide}
5313 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005314 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005315
5316 /**
5317 * Checks whether the phone is in silent mode, with or without vibrate.
5318 *
5319 * @return true if phone is in silent mode, with or without vibrate.
5320 *
5321 * @see #getRingerMode()
5322 *
5323 * @hide pending API Council approval
5324 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005325 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005326 public boolean isSilentMode() {
5327 int ringerMode = getRingerMode();
5328 boolean silentMode =
5329 (ringerMode == RINGER_MODE_SILENT) ||
5330 (ringerMode == RINGER_MODE_VIBRATE);
5331 return silentMode;
5332 }
5333
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005334 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5335 // class is not used by other parts of the framework, which instead use definitions and methods
5336 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5337
Eric Laurent948d3272014-05-16 15:18:45 -07005338 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005339 * The audio device code for representing "no device." */
5340 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5341 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005342 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005343 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5344 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5345 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5346 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005347 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005348 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005349 /** @hide
5350 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005351 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005352 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005353 /** @hide
5354 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005355 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005356 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005357 /** @hide
5358 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005359 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005360 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005361 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005362 * The audio output device code for a USB headphone with attached microphone */
5363 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5364 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005365 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005366 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005367 /** @hide
5368 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5369 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005370 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005371 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005372 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5373 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005374 /** @hide
5375 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005376 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5377 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005378 /** @hide
5379 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005380 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005381 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005382 /** @hide
5383 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005384 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005385 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5386 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005387 /** @hide
5388 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005389 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005390 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5391 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005392 /** @hide
5393 * The audio output device code for S/PDIF (legacy) or HDMI
5394 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005395 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005396 /** @hide
5397 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005398 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005399 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5400 /** @hide
5401 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005402 * docking station
5403 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005404 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005405 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005406 /** @hide
5407 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005408 * docking station
5409 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005410 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005411 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005412 /** @hide
5413 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005414 * mode and the Android device in USB device mode
5415 */
5416 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005417 /** @hide
5418 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005419 * mode and the Android device in USB host mode
5420 */
5421 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005422 /** @hide
5423 * The audio output device code for projection output.
5424 */
5425 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5426 /** @hide
5427 * The audio output device code the telephony voice TX path.
5428 */
5429 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5430 /** @hide
5431 * The audio output device code for an analog jack with line impedance detected.
5432 */
5433 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5434 /** @hide
5435 * The audio output device code for HDMI Audio Return Channel.
5436 */
5437 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5438 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005439 * The audio output device code for HDMI enhanced Audio Return Channel.
5440 */
5441 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5442 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005443 * The audio output device code for S/PDIF digital connection.
5444 */
5445 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5446 /** @hide
5447 * The audio output device code for built-in FM transmitter.
5448 */
5449 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5450 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005451 * The audio output device code for echo reference injection point.
5452 */
5453 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5454 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005455 * The audio output device code for a BLE audio headset.
5456 */
5457 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5458 /** @hide
5459 * The audio output device code for a BLE audio speaker.
5460 */
5461 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5462 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01005463 * The audio output device code for a BLE audio brodcast group.
5464 */
5465 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
5466 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005467 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005468 * used in the future in a set method to select whatever default device is chosen by the
5469 * platform-specific implementation.
5470 */
5471 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5472
Eric Laurent948d3272014-05-16 15:18:45 -07005473 /** @hide
5474 * The audio input device code for default built-in microphone
5475 */
5476 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5477 /** @hide
5478 * The audio input device code for a Bluetooth SCO headset
5479 */
5480 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5481 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5482 /** @hide
5483 * The audio input device code for wired headset microphone
5484 */
5485 public static final int DEVICE_IN_WIRED_HEADSET =
5486 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5487 /** @hide
5488 * The audio input device code for HDMI
5489 */
5490 public static final int DEVICE_IN_HDMI =
5491 AudioSystem.DEVICE_IN_HDMI;
5492 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005493 * The audio input device code for HDMI ARC
5494 */
5495 public static final int DEVICE_IN_HDMI_ARC =
5496 AudioSystem.DEVICE_IN_HDMI_ARC;
5497
5498 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005499 * The audio input device code for HDMI EARC
5500 */
5501 public static final int DEVICE_IN_HDMI_EARC =
5502 AudioSystem.DEVICE_IN_HDMI_EARC;
5503
5504 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005505 * The audio input device code for telephony voice RX path
5506 */
5507 public static final int DEVICE_IN_TELEPHONY_RX =
5508 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5509 /** @hide
5510 * The audio input device code for built-in microphone pointing to the back
5511 */
5512 public static final int DEVICE_IN_BACK_MIC =
5513 AudioSystem.DEVICE_IN_BACK_MIC;
5514 /** @hide
5515 * The audio input device code for analog from a docking station
5516 */
5517 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5518 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5519 /** @hide
5520 * The audio input device code for digital from a docking station
5521 */
5522 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5523 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5524 /** @hide
5525 * The audio input device code for a USB audio accessory. The accessory is in USB host
5526 * mode and the Android device in USB device mode
5527 */
5528 public static final int DEVICE_IN_USB_ACCESSORY =
5529 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5530 /** @hide
5531 * The audio input device code for a USB audio device. The device is in USB device
5532 * mode and the Android device in USB host mode
5533 */
5534 public static final int DEVICE_IN_USB_DEVICE =
5535 AudioSystem.DEVICE_IN_USB_DEVICE;
5536 /** @hide
5537 * The audio input device code for a FM radio tuner
5538 */
5539 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5540 /** @hide
5541 * The audio input device code for a TV tuner
5542 */
5543 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5544 /** @hide
5545 * The audio input device code for an analog jack with line impedance detected
5546 */
5547 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5548 /** @hide
5549 * The audio input device code for a S/PDIF digital connection
5550 */
5551 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005552 /** @hide
5553 * The audio input device code for audio loopback
5554 */
5555 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005556 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005557 * The audio input device code for an echo reference capture point.
5558 */
5559 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5560 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005561 * The audio input device code for a BLE audio headset.
5562 */
5563 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005564
5565 /**
5566 * Return true if the device code corresponds to an output device.
5567 * @hide
5568 */
5569 public static boolean isOutputDevice(int device)
5570 {
5571 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5572 }
5573
5574 /**
5575 * Return true if the device code corresponds to an input device.
5576 * @hide
5577 */
5578 public static boolean isInputDevice(int device)
5579 {
5580 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5581 }
5582
5583
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005584 /**
5585 * Return the enabled devices for the specified output stream type.
5586 *
5587 * @param streamType The stream type to query. One of
5588 * {@link #STREAM_VOICE_CALL},
5589 * {@link #STREAM_SYSTEM},
5590 * {@link #STREAM_RING},
5591 * {@link #STREAM_MUSIC},
5592 * {@link #STREAM_ALARM},
5593 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005594 * {@link #STREAM_DTMF},
5595 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005596 *
5597 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5598 * stream. Zero or more of
5599 * {@link #DEVICE_OUT_EARPIECE},
5600 * {@link #DEVICE_OUT_SPEAKER},
5601 * {@link #DEVICE_OUT_WIRED_HEADSET},
5602 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5603 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5604 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5605 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5606 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5607 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5608 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005609 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005610 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5611 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005612 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5613 * {@link #DEVICE_OUT_USB_DEVICE}.
5614 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5615 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5616 * {@link #DEVICE_OUT_LINE}.
5617 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005618 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005619 * {@link #DEVICE_OUT_SPDIF}.
5620 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005621 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5622 *
5623 * The implementation may support additional device codes beyond those listed, so
5624 * the application should ignore any bits which it does not recognize.
5625 * Note that the information may be imprecise when the implementation
5626 * cannot distinguish whether a particular device is enabled.
5627 *
Andy Hungb11e4c72021-04-13 19:31:00 -07005628 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
5629 * will have multi-bit device types.
5630 * Prefer to use {@link #getDevicesForAttributes()} instead,
5631 * noting that getDevicesForStream() has a few small discrepancies
5632 * for better volume handling.
5633 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005634 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005635 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07005636 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005637 public int getDevicesForStream(int streamType) {
5638 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07005639 case STREAM_VOICE_CALL:
5640 case STREAM_SYSTEM:
5641 case STREAM_RING:
5642 case STREAM_MUSIC:
5643 case STREAM_ALARM:
5644 case STREAM_NOTIFICATION:
5645 case STREAM_DTMF:
5646 case STREAM_ACCESSIBILITY:
5647 final IAudioService service = getService();
5648 try {
5649 return service.getDeviceMaskForStream(streamType);
5650 } catch (RemoteException e) {
5651 throw e.rethrowFromSystemServer();
5652 }
5653 default:
5654 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005655 }
5656 }
5657
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005658 /**
5659 * @hide
5660 * Get the audio devices that would be used for the routing of the given audio attributes.
5661 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5662 * @return an empty list if there was an issue with the request, a list of audio devices
5663 * otherwise (typically one device, except for duplicated paths).
5664 */
5665 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005666 @RequiresPermission(anyOf = {
5667 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5668 android.Manifest.permission.QUERY_AUDIO_STATE
5669 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005670 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005671 @NonNull AudioAttributes attributes) {
5672 Objects.requireNonNull(attributes);
5673 final IAudioService service = getService();
5674 try {
5675 return service.getDevicesForAttributes(attributes);
5676 } catch (RemoteException e) {
5677 throw e.rethrowFromSystemServer();
5678 }
5679 }
5680
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005681 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01005682 * Get the audio devices that would be used for the routing of the given audio attributes.
5683 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
5684 * the specified {@link AudioAttributes}.
5685 * The audio routing can change if audio devices are physically connected or disconnected or
5686 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
5687 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5688 * @return an empty list if there was an issue with the request, a list of
5689 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
5690 */
5691 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
5692 @NonNull AudioAttributes attributes) {
5693 final List<AudioDeviceAttributes> devicesForAttributes;
5694 try {
5695 Objects.requireNonNull(attributes);
5696 final IAudioService service = getService();
5697 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
5698 } catch (Exception e) {
5699 Log.i(TAG, "No audio devices available for specified attributes.");
5700 return Collections.emptyList();
5701 }
5702
5703 // Map from AudioDeviceAttributes to AudioDeviceInfo
5704 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
5705 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
5706 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
5707 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
5708 if (deviceForAttributes.getType() == deviceInfo.getType()
5709 && TextUtils.equals(deviceForAttributes.getAddress(),
5710 deviceInfo.getAddress())) {
5711 deviceInfosForAttributes.add(deviceInfo);
5712 }
5713 }
5714 }
5715 return Collections.unmodifiableList(deviceInfosForAttributes);
5716 }
5717
5718 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005719 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005720 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02005721 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5722 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005723 */
5724 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5725 /**
5726 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005727 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02005728 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005729 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005730 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005731 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5732 /**
5733 * @hide
5734 * Volume behavior for an audio device where the volume is always set to provide no attenuation
5735 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005736 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005737 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005738 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005739 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5740 /**
5741 * @hide
5742 * Volume behavior for an audio device where the volume is either set to muted, or to provide
5743 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005744 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005745 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005746 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005747 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5748 /**
5749 * @hide
5750 * Volume behavior for an audio device where no software attenuation is applied, and
5751 * the volume is kept synchronized between the host and the device itself through a
5752 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005753 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005754 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005755 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005756 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5757 /**
5758 * @hide
5759 * Volume behavior for an audio device where no software attenuation is applied, and
5760 * the volume is kept synchronized between the host and the device itself through a
5761 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5762 * normal vs in phone call).
5763 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02005764 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005765 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005766 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005767 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5768
5769 /** @hide */
5770 @IntDef({
5771 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5772 DEVICE_VOLUME_BEHAVIOR_FULL,
5773 DEVICE_VOLUME_BEHAVIOR_FIXED,
5774 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5775 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5776 })
5777 @Retention(RetentionPolicy.SOURCE)
5778 public @interface DeviceVolumeBehavior {}
5779
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005780 /** @hide */
5781 @IntDef({
5782 DEVICE_VOLUME_BEHAVIOR_UNSET,
5783 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5784 DEVICE_VOLUME_BEHAVIOR_FULL,
5785 DEVICE_VOLUME_BEHAVIOR_FIXED,
5786 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5787 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5788 })
5789 @Retention(RetentionPolicy.SOURCE)
5790 public @interface DeviceVolumeBehaviorState {}
5791
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005792 /**
5793 * @hide
5794 * Throws IAE on an invalid volume behavior value
5795 * @param volumeBehavior behavior value to check
5796 */
5797 public static void enforceValidVolumeBehavior(int volumeBehavior) {
5798 switch (volumeBehavior) {
5799 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5800 case DEVICE_VOLUME_BEHAVIOR_FULL:
5801 case DEVICE_VOLUME_BEHAVIOR_FIXED:
5802 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5803 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5804 return;
5805 default:
5806 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5807 }
5808 }
5809
5810 /**
5811 * @hide
5812 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005813 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5814 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5815 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5816 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5817 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5818 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005819 * @param deviceVolumeBehavior one of the device behaviors
5820 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005821 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005822 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5823 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5824 @DeviceVolumeBehavior int deviceVolumeBehavior) {
5825 // verify arguments (validity of device type is enforced in server)
5826 Objects.requireNonNull(device);
5827 enforceValidVolumeBehavior(deviceVolumeBehavior);
5828 // communicate with service
5829 final IAudioService service = getService();
5830 try {
5831 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5832 mApplicationContext.getOpPackageName());
5833 } catch (RemoteException e) {
5834 throw e.rethrowFromSystemServer();
5835 }
5836 }
5837
5838 /**
5839 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005840 * Returns the volume device behavior for the given audio device
5841 * @param device the audio device
5842 * @return the volume behavior for the device
5843 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005844 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005845 @RequiresPermission(anyOf = {
5846 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5847 android.Manifest.permission.QUERY_AUDIO_STATE
5848 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02005849 public @DeviceVolumeBehavior
5850 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005851 // verify arguments (validity of device type is enforced in server)
5852 Objects.requireNonNull(device);
5853 // communicate with service
5854 final IAudioService service = getService();
5855 try {
5856 return service.getDeviceVolumeBehavior(device);
5857 } catch (RemoteException e) {
5858 throw e.rethrowFromSystemServer();
5859 }
5860 }
5861
kholoud mohamed37839212021-03-15 16:49:06 +00005862 /**
5863 * @hide
5864 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5865 */
5866 @TestApi
5867 @RequiresPermission(anyOf = {
5868 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5869 android.Manifest.permission.QUERY_AUDIO_STATE
5870 })
5871 public boolean isFullVolumeDevice() {
5872 final AudioAttributes attributes = new AudioAttributes.Builder()
5873 .setUsage(AudioAttributes.USAGE_MEDIA)
5874 .build();
5875 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5876 for (AudioDeviceAttributes device : devices) {
5877 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5878 return true;
5879 }
5880 }
5881 return false;
5882 }
5883
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005884 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005885 * Indicate wired accessory connection state change.
5886 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5887 * @param state new connection state: 1 connected, 0 disconnected
5888 * @param name device name
5889 * {@hide}
5890 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005891 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07005892 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005893 public void setWiredDeviceConnectionState(int device, int state, String address,
5894 String name) {
5895 final IAudioService service = getService();
5896 int role = isOutputDevice(device)
5897 ? AudioDeviceAttributes.ROLE_OUTPUT : AudioDeviceAttributes.ROLE_INPUT;
5898 AudioDeviceAttributes attributes = new AudioDeviceAttributes(
5899 role, AudioDeviceInfo.convertInternalDeviceToDeviceType(device), address,
5900 name, new ArrayList<>()/*mAudioProfiles*/, new ArrayList<>()/*mAudioDescriptors*/);
5901 setWiredDeviceConnectionState(attributes, state);
5902 }
5903
5904 /**
5905 * Indicate wired accessory connection state change and attributes.
5906 * @param state new connection state: 1 connected, 0 disconnected
5907 * @param attributes attributes of the connected device
5908 * {@hide}
5909 */
5910 @UnsupportedAppUsage
5911 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5912 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005913 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005914 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005915 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07005916 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005917 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005918 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005919 }
5920 }
5921
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00005922 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08005923 * Indicate wired accessory connection state change.
5924 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
5925 * @param connected true for connected, false for disconnected
5926 * {@hide}
5927 */
5928 @TestApi
5929 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5930 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
5931 boolean connected) {
5932 try {
5933 getService().setTestDeviceConnectionState(device, connected);
5934 } catch (RemoteException e) {
5935 throw e.rethrowFromSystemServer();
5936 }
5937 }
5938
5939 /**
wescande7c17ba0c2021-07-30 16:46:14 +02005940 * Indicate Bluetooth profile connection state change.
5941 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
5942 * <code>previousDevice</code>
5943 * This operation is asynchronous.
5944 *
5945 * @param newDevice Bluetooth device connected or null if there is no new devices
5946 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
5947 * devices
William Escandeac11d772022-01-25 18:01:15 +01005948 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005949 * {@hide}
5950 */
wescande7c17ba0c2021-07-30 16:46:14 +02005951 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5952 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
5953 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01005954 @Nullable BluetoothDevice previousDevice,
5955 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005956 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005957 try {
wescande7c17ba0c2021-07-30 16:46:14 +02005958 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005959 } catch (RemoteException e) {
5960 throw e.rethrowFromSystemServer();
5961 }
5962 }
5963
Jeff Sharkey098d5802012-04-26 17:30:34 -07005964 /** {@hide} */
5965 public IRingtonePlayer getRingtonePlayer() {
5966 try {
5967 return getService().getRingtonePlayer();
5968 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005969 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005970 }
5971 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005972
5973 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005974 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07005975 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
5976 * should use this value as a default, and offer the user the option to override it.
5977 * The low latency output stream is typically either the device's primary output stream,
5978 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005979 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005980 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005981 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5982 "android.media.property.OUTPUT_SAMPLE_RATE";
5983
5984 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005985 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07005986 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
5987 * should use this value as a minimum, and offer the user the option to override it.
5988 * The low latency output stream is typically either the device's primary output stream,
5989 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005990 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005991 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005992 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
5993 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
5994
5995 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07005996 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
5997 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5998 */
5999 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6000 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6001
6002 /**
6003 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6004 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6005 */
6006 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6007 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6008
6009 /**
ragoa7cc59c2015-12-02 11:31:15 -08006010 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6011 * available and supported with the expected frequency range and level response.
6012 */
6013 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6014 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6015 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006016 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006017 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006018 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6019 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006020 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6021 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6022 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006023 * @return A string representing the associated value for that property key,
6024 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006025 */
6026 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006027 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6028 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6029 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6030 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6031 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6032 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006033 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006034 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6035 // not found.
6036 return String.valueOf(getContext().getResources().getBoolean(
6037 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006038 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006039 return String.valueOf(getContext().getResources().getBoolean(
6040 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006041 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6042 return String.valueOf(getContext().getResources().getBoolean(
6043 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006044 } else {
6045 // null or unknown key
6046 return null;
6047 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006048 }
6049
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006050 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006051 * @hide
6052 * Sets an additional audio output device delay in milliseconds.
6053 *
6054 * The additional output delay is a request to the output device to
6055 * delay audio presentation (generally with respect to video presentation for better
6056 * synchronization).
6057 * It may not be supported by all output devices,
6058 * and typically increases the audio latency by the amount of additional
6059 * audio delay requested.
6060 *
6061 * If additional audio delay is supported by an audio output device,
6062 * it is expected to be supported for all output streams (and configurations)
6063 * opened on that device.
6064 *
6065 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006066 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006067 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6068 * @return true if successful, false if the device does not support output device delay
6069 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6070 */
6071 @SystemApi
6072 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6073 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006074 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006075 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006076 try {
6077 return getService().setAdditionalOutputDeviceDelay(
6078 new AudioDeviceAttributes(device), delayMillis);
6079 } catch (RemoteException e) {
6080 throw e.rethrowFromSystemServer();
6081 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006082 }
6083
6084 /**
6085 * @hide
6086 * Returns the current additional audio output device delay in milliseconds.
6087 *
6088 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6089 * @return the additional output device delay. This is a non-negative number.
6090 * {@code 0} is returned if unsupported.
6091 */
6092 @SystemApi
6093 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006094 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006095 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006096 try {
6097 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6098 } catch (RemoteException e) {
6099 throw e.rethrowFromSystemServer();
6100 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006101 }
6102
6103 /**
6104 * @hide
6105 * Returns the maximum additional audio output device delay in milliseconds.
6106 *
6107 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6108 * @return the maximum output device delay in milliseconds that can be set.
6109 * This is a non-negative number
6110 * representing the additional audio delay supported for the device.
6111 * {@code 0} is returned if unsupported.
6112 */
6113 @SystemApi
6114 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006115 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006116 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006117 try {
6118 return getService().getMaxAdditionalOutputDeviceDelay(
6119 new AudioDeviceAttributes(device));
6120 } catch (RemoteException e) {
6121 throw e.rethrowFromSystemServer();
6122 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006123 }
6124
6125 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006126 * Returns the estimated latency for the given stream type in milliseconds.
6127 *
6128 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6129 * a better solution.
6130 * @hide
6131 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006132 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006133 public int getOutputLatency(int streamType) {
6134 return AudioSystem.getOutputLatency(streamType);
6135 }
6136
John Spurlock3346a802014-05-20 16:25:37 -04006137 /**
6138 * Registers a global volume controller interface. Currently limited to SystemUI.
6139 *
6140 * @hide
6141 */
6142 public void setVolumeController(IVolumeController controller) {
6143 try {
6144 getService().setVolumeController(controller);
6145 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006146 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006147 }
6148 }
6149
6150 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006151 * Notify audio manager about volume controller visibility changes.
6152 * Currently limited to SystemUI.
6153 *
6154 * @hide
6155 */
6156 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6157 try {
6158 getService().notifyVolumeControllerVisible(controller, visible);
6159 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006160 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006161 }
6162 }
6163
6164 /**
John Spurlock3346a802014-05-20 16:25:37 -04006165 * Only useful for volume controllers.
6166 * @hide
6167 */
John Spurlock3346a802014-05-20 16:25:37 -04006168 public boolean isStreamAffectedByRingerMode(int streamType) {
6169 try {
6170 return getService().isStreamAffectedByRingerMode(streamType);
6171 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006172 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006173 }
6174 }
6175
6176 /**
6177 * Only useful for volume controllers.
6178 * @hide
6179 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006180 public boolean isStreamAffectedByMute(int streamType) {
6181 try {
6182 return getService().isStreamAffectedByMute(streamType);
6183 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006184 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006185 }
6186 }
6187
6188 /**
6189 * Only useful for volume controllers.
6190 * @hide
6191 */
John Spurlock3346a802014-05-20 16:25:37 -04006192 public void disableSafeMediaVolume() {
6193 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006194 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006195 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006196 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006197 }
6198 }
Eric Laurenta198a292014-02-18 16:26:17 -08006199
6200 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006201 * Only useful for volume controllers.
6202 * @hide
6203 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006204 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006205 public void setRingerModeInternal(int ringerMode) {
6206 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006207 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006208 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006209 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006210 }
6211 }
6212
6213 /**
6214 * Only useful for volume controllers.
6215 * @hide
6216 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006217 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006218 public int getRingerModeInternal() {
6219 try {
6220 return getService().getRingerModeInternal();
6221 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006222 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006223 }
6224 }
6225
6226 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006227 * Only useful for volume controllers.
6228 * @hide
6229 */
6230 public void setVolumePolicy(VolumePolicy policy) {
6231 try {
6232 getService().setVolumePolicy(policy);
6233 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006234 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006235 }
6236 }
6237
6238 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006239 * Set Hdmi Cec system audio mode.
6240 *
6241 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006242 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006243 * @hide
6244 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006245 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006246 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006247 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006248 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006249 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006250 }
6251 }
6252
6253 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006254 * Returns true if Hdmi Cec system audio mode is supported.
6255 *
6256 * @hide
6257 */
6258 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006259 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006260 public boolean isHdmiSystemAudioSupported() {
6261 try {
6262 return getService().isHdmiSystemAudioSupported();
6263 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006264 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006265 }
6266 }
6267
6268 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006269 * Return codes for listAudioPorts(), createAudioPatch() ...
6270 */
6271
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006272 /** @hide */
6273 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006274 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006275 /**
6276 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006277 */
6278 public static final int ERROR = AudioSystem.ERROR;
6279 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006280 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006281 */
6282 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6283 /** @hide
6284 */
6285 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6286 /** @hide
6287 */
6288 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6289 /** @hide
6290 */
6291 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006292 /**
6293 * An error code indicating that the object reporting it is no longer valid and needs to
6294 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006295 */
6296 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6297
6298 /**
6299 * Returns a list of descriptors for all audio ports managed by the audio framework.
6300 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6301 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6302 * See AudioPort for a list of attributes of each audio port.
6303 * @param ports An AudioPort ArrayList where the list will be returned.
6304 * @hide
6305 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006306 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006307 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006308 return updateAudioPortCache(ports, null, null);
6309 }
6310
6311 /**
6312 * Returns a list of descriptors for all audio ports managed by the audio framework as
6313 * it was before the last update calback.
6314 * @param ports An AudioPort ArrayList where the list will be returned.
6315 * @hide
6316 */
6317 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6318 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006319 }
6320
6321 /**
6322 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6323 * @see listAudioPorts(ArrayList<AudioPort>)
6324 * @hide
6325 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006326 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006327 if (devices == null) {
6328 return ERROR_BAD_VALUE;
6329 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006330 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006331 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006332 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006333 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006334 }
6335 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006336 }
6337
6338 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006339 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6340 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6341 * @hide
6342 */
6343 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6344 if (devices == null) {
6345 return ERROR_BAD_VALUE;
6346 }
6347 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6348 int status = updateAudioPortCache(null, null, ports);
6349 if (status == SUCCESS) {
6350 filterDevicePorts(ports, devices);
6351 }
6352 return status;
6353 }
6354
6355 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6356 ArrayList<AudioDevicePort> devices) {
6357 devices.clear();
6358 for (int i = 0; i < ports.size(); i++) {
6359 if (ports.get(i) instanceof AudioDevicePort) {
6360 devices.add((AudioDevicePort)ports.get(i));
6361 }
6362 }
6363 }
6364
6365 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006366 * Create a connection between two or more devices. The framework will reject the request if
6367 * device types are not compatible or the implementation does not support the requested
6368 * configuration.
6369 * NOTE: current implementation is limited to one source and one sink per patch.
6370 * @param patch AudioPatch array where the newly created patch will be returned.
6371 * As input, if patch[0] is not null, the specified patch will be replaced by the
6372 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6373 * patch and allows the implementation to optimize transitions.
6374 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6375 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6376 *
6377 * @return - {@link #SUCCESS} if connection is successful.
6378 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6379 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6380 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6381 * a patch.
6382 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6383 * - {@link #ERROR} if patch cannot be connected for any other reason.
6384 *
6385 * patch[0] contains the newly created patch
6386 * @hide
6387 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006388 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006389 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006390 AudioPortConfig[] sources,
6391 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006392 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006393 }
6394
6395 /**
6396 * Releases an existing audio patch connection.
6397 * @param patch The audio patch to disconnect.
6398 * @return - {@link #SUCCESS} if disconnection is successful.
6399 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6400 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6401 * a patch.
6402 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6403 * - {@link #ERROR} if patch cannot be released for any other reason.
6404 * @hide
6405 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006406 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006407 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006408 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006409 }
6410
6411 /**
6412 * List all existing connections between audio ports.
6413 * @param patches An AudioPatch array where the list will be returned.
6414 * @hide
6415 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006416 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006417 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006418 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006419 }
6420
6421 /**
6422 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6423 * AudioGain.buildConfig()
6424 * @hide
6425 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006426 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006427 if (port == null || gain == null) {
6428 return ERROR_BAD_VALUE;
6429 }
6430 AudioPortConfig activeConfig = port.activeConfig();
6431 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6432 activeConfig.channelMask(), activeConfig.format(), gain);
6433 config.mConfigMask = AudioPortConfig.GAIN;
6434 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006435 }
6436
6437 /**
6438 * Listener registered by client to be notified upon new audio port connections,
6439 * disconnections or attributes update.
6440 * @hide
6441 */
6442 public interface OnAudioPortUpdateListener {
6443 /**
6444 * Callback method called upon audio port list update.
6445 * @param portList the updated list of audio ports
6446 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006447 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006448
6449 /**
6450 * Callback method called upon audio patch list update.
6451 * @param patchList the updated list of audio patches
6452 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006453 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006454
6455 /**
6456 * Callback method called when the mediaserver dies
6457 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006458 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006459 }
6460
6461 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006462 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006463 * @hide
6464 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006465 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006466 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006467 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006468 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006469 }
6470
6471 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006472 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006473 * @hide
6474 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006475 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006476 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006477 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006478 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006479
6480 //
6481 // AudioPort implementation
6482 //
6483
6484 static final int AUDIOPORT_GENERATION_INIT = 0;
Eric Laurentf076db42015-01-14 13:23:27 -08006485 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT);
6486 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006487 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurentf076db42015-01-14 13:23:27 -08006488 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006489
Eric Laurentf076db42015-01-14 13:23:27 -08006490 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006491 int generation;
Eric Laurentf076db42015-01-14 13:23:27 -08006492 synchronized (sAudioPortGeneration) {
6493 generation = sAudioPortGeneration;
6494 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006495 }
6496 return generation;
6497 }
6498
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006499 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6500 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006501 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006502 synchronized (sAudioPortGeneration) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006503
Eric Laurentf076db42015-01-14 13:23:27 -08006504 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006505 int[] patchGeneration = new int[1];
6506 int[] portGeneration = new int[1];
6507 int status;
6508 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6509 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6510
6511 do {
6512 newPorts.clear();
6513 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006514 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006515 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006516 return status;
6517 }
6518 newPatches.clear();
6519 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006520 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006521 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006522 return status;
6523 }
jiabinc4ecaa52017-09-26 14:28:41 -07006524 // Loop until patch generation is the same as port generation unless audio ports
6525 // and audio patches are not null.
6526 } while (patchGeneration[0] != portGeneration[0]
6527 && (ports == null || patches == null));
6528 // If the patch generation doesn't equal port generation, return ERROR here in case
6529 // of mismatch between audio ports and audio patches.
6530 if (patchGeneration[0] != portGeneration[0]) {
6531 return ERROR;
6532 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006533
6534 for (int i = 0; i < newPatches.size(); i++) {
6535 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006536 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6537 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006538 newPatches.get(i).sources()[j] = portCfg;
6539 }
6540 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006541 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6542 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006543 newPatches.get(i).sinks()[j] = portCfg;
6544 }
6545 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006546 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6547 AudioPatch newPatch = i.next();
6548 boolean hasInvalidPort = false;
6549 for (AudioPortConfig portCfg : newPatch.sources()) {
6550 if (portCfg == null) {
6551 hasInvalidPort = true;
6552 break;
6553 }
6554 }
6555 for (AudioPortConfig portCfg : newPatch.sinks()) {
6556 if (portCfg == null) {
6557 hasInvalidPort = true;
6558 break;
6559 }
6560 }
6561 if (hasInvalidPort) {
6562 // Temporarily remove patches with invalid ports. One who created the patch
6563 // is responsible for dealing with the port change.
6564 i.remove();
6565 }
6566 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006567
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006568 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006569 sAudioPortsCached = newPorts;
6570 sAudioPatchesCached = newPatches;
6571 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006572 }
6573 if (ports != null) {
6574 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006575 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006576 }
6577 if (patches != null) {
6578 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006579 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006580 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006581 if (previousPorts != null) {
6582 previousPorts.clear();
6583 previousPorts.addAll(sPreviousAudioPortsCached);
6584 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006585 }
6586 return SUCCESS;
6587 }
6588
Eric Laurentf076db42015-01-14 13:23:27 -08006589 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006590 AudioPort port = portCfg.port();
6591 int k;
6592 for (k = 0; k < ports.size(); k++) {
6593 // compare handles because the port returned by JNI is not of the correct
6594 // subclass
6595 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006596 port = ports.get(k);
6597 break;
6598 }
6599 }
6600 if (k == ports.size()) {
6601 // this hould never happen
6602 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
6603 return null;
6604 }
6605 AudioGainConfig gainCfg = portCfg.gain();
6606 if (gainCfg != null) {
6607 AudioGain gain = port.gain(gainCfg.index());
6608 gainCfg = gain.buildConfig(gainCfg.mode(),
6609 gainCfg.channelMask(),
6610 gainCfg.values(),
6611 gainCfg.rampDurationMs());
6612 }
6613 return port.buildConfig(portCfg.samplingRate(),
6614 portCfg.channelMask(),
6615 portCfg.format(),
6616 gainCfg);
6617 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006618
6619 private OnAmPortUpdateListener mPortListener = null;
6620
6621 /**
6622 * The message sent to apps when the contents of the device list changes if they provide
Andrew Solovay5c05ded2018-10-02 14:14:42 -07006623 * a {@link Handler} object to addOnAudioDeviceConnectionListener().
Paul McLeane3383cc2015-05-08 11:41:20 -07006624 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006625 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6626 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6627 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006628
Paul McLean8e6c9f42015-05-19 11:13:41 -07006629 /**
6630 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6631 */
Jack He89f97982018-05-02 19:10:56 -07006632 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006633 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006634
6635 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006636 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6637 * the results list to only those device types they are interested in.
6638 */
6639 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07006640 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6641 * source (i.e. input) audio devices.
6642 */
6643 public static final int GET_DEVICES_INPUTS = 0x0001;
6644
6645 /**
6646 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6647 * sink (i.e. output) audio devices.
6648 */
6649 public static final int GET_DEVICES_OUTPUTS = 0x0002;
6650
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006651 /** @hide */
6652 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6653 GET_DEVICES_INPUTS,
6654 GET_DEVICES_OUTPUTS }
6655 )
6656 @Retention(RetentionPolicy.SOURCE)
6657 public @interface AudioDeviceRole {}
6658
Paul McLeane3383cc2015-05-08 11:41:20 -07006659 /**
6660 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6661 * source and sink devices.
6662 */
6663 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6664
6665 /**
6666 * Determines if a given AudioDevicePort meets the specified filter criteria.
6667 * @param port The port to test.
6668 * @param flags A set of bitflags specifying the criteria to test.
6669 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6670 **/
6671 private static boolean checkFlags(AudioDevicePort port, int flags) {
6672 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6673 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6674 }
6675
Paul McLean11354572015-08-07 12:50:48 -06006676 private static boolean checkTypes(AudioDevicePort port) {
6677 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07006678 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06006679 }
6680
Paul McLeane3383cc2015-05-08 11:41:20 -07006681 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006682 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6683 * currently connected to the system and meeting the criteria specified in the
6684 * <code>flags</code> parameter.
Paul McLeane3383cc2015-05-08 11:41:20 -07006685 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006686 * @see #GET_DEVICES_OUTPUTS
6687 * @see #GET_DEVICES_INPUTS
6688 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07006689 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6690 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006691 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006692 return getDevicesStatic(flags);
6693 }
6694
Paul McLean8e6c9f42015-05-19 11:13:41 -07006695 /**
6696 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6697 * objects from the current (internal) AudioDevicePort list.
6698 */
Paul McLean03346882015-05-12 15:36:56 -07006699 private static AudioDeviceInfo[]
6700 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006701
Paul McLean8e6c9f42015-05-19 11:13:41 -07006702 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07006703 int numRecs = 0;
6704 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006705 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006706 numRecs++;
6707 }
6708 }
6709
Paul McLean8e6c9f42015-05-19 11:13:41 -07006710 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07006711 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6712 int slot = 0;
6713 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006714 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006715 deviceList[slot++] = new AudioDeviceInfo(port);
6716 }
6717 }
6718
6719 return deviceList;
6720 }
6721
Paul McLean03346882015-05-12 15:36:56 -07006722 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07006723 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6724 * the add/remove callback mechanism to provide a list of the newly added or removed devices
6725 * rather than the whole list and make the app figure it out.
6726 * Note that calling this method with:
6727 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6728 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07006729 */
6730 private static AudioDeviceInfo[] calcListDeltas(
6731 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6732
6733 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6734
6735 AudioDevicePort cur_port = null;
6736 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6737 boolean cur_port_found = false;
6738 cur_port = ports_B.get(cur_index);
6739 for (int prev_index = 0;
6740 prev_index < ports_A.size() && !cur_port_found;
6741 prev_index++) {
6742 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6743 }
6744
6745 if (!cur_port_found) {
6746 delta_ports.add(cur_port);
6747 }
6748 }
6749
6750 return infoListFromPortList(delta_ports, flags);
6751 }
6752
Paul McLeane3383cc2015-05-08 11:41:20 -07006753 /**
Paul McLean03346882015-05-12 15:36:56 -07006754 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6755 * connected to the system and meeting the criteria specified in the <code>flags</code>
6756 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006757 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07006758 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006759 * @see #GET_DEVICES_OUTPUTS
6760 * @see #GET_DEVICES_INPUTS
6761 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07006762 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6763 * @hide
6764 */
6765 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6766 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6767 int status = AudioManager.listAudioDevicePorts(ports);
6768 if (status != AudioManager.SUCCESS) {
6769 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07006770 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07006771 }
6772
6773 return infoListFromPortList(ports, flags);
6774 }
6775
6776 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07006777 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6778 * @param portId The audio port ID to look up for.
6779 * @param flags A set of bitflags specifying the criteria to test.
6780 * @see #GET_DEVICES_OUTPUTS
6781 * @see #GET_DEVICES_INPUTS
6782 * @see #GET_DEVICES_ALL
6783 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6784 * @hide
6785 */
6786 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6787 if (portId == 0) {
6788 return null;
6789 }
6790 AudioDeviceInfo[] devices = getDevicesStatic(flags);
6791 for (AudioDeviceInfo device : devices) {
6792 if (device.getId() == portId) {
6793 return device;
6794 }
6795 }
6796 return null;
6797 }
6798
6799 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006800 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07006801 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006802 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6803 * notifications.
6804 * @param handler Specifies the {@link Handler} object for the thread on which to execute
6805 * the callback. If <code>null</code>, the {@link Handler} associated with the main
6806 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07006807 */
Paul McLean03346882015-05-12 15:36:56 -07006808 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08006809 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07006810 synchronized (mDeviceCallbacks) {
6811 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006812 if (mDeviceCallbacks.size() == 0) {
6813 if (mPortListener == null) {
6814 mPortListener = new OnAmPortUpdateListener();
6815 }
6816 registerAudioPortUpdateListener(mPortListener);
6817 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006818 NativeEventHandlerDelegate delegate =
6819 new NativeEventHandlerDelegate(callback, handler);
6820 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07006821 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07006822 }
6823 }
6824 }
6825
6826 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006827 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07006828 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006829 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08006830 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07006831 */
Paul McLean03346882015-05-12 15:36:56 -07006832 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6833 synchronized (mDeviceCallbacks) {
6834 if (mDeviceCallbacks.containsKey(callback)) {
6835 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07006836 if (mDeviceCallbacks.size() == 0) {
6837 unregisterAudioPortUpdateListener(mPortListener);
6838 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006839 }
6840 }
6841 }
6842
jiabinc0f49442018-01-05 10:23:50 -08006843 /**
6844 * Set port id for microphones by matching device type and address.
6845 * @hide
6846 */
6847 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6848 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6849 for (int i = microphones.size() - 1; i >= 0; i--) {
6850 boolean foundPortId = false;
6851 for (AudioDeviceInfo device : devices) {
6852 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6853 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6854 microphones.get(i).setId(device.getId());
6855 foundPortId = true;
6856 break;
6857 }
6858 }
6859 if (!foundPortId) {
6860 Log.i(TAG, "Failed to find port id for device with type:"
6861 + microphones.get(i).getType() + " address:"
6862 + microphones.get(i).getAddress());
6863 microphones.remove(i);
6864 }
6865 }
6866 }
6867
6868 /**
jiabin589a2362018-02-22 16:21:53 -08006869 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6870 * @hide
6871 */
6872 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6873 int deviceType = deviceInfo.getType();
6874 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6875 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6876 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6877 : MicrophoneInfo.LOCATION_PERIPHERAL;
6878 MicrophoneInfo microphone = new MicrophoneInfo(
6879 deviceInfo.getPort().name() + deviceInfo.getId(),
6880 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6881 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6882 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6883 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6884 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6885 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6886 microphone.setId(deviceInfo.getId());
6887 return microphone;
6888 }
6889
6890 /**
jiabind0be5b22018-04-10 14:10:04 -07006891 * Add {@link MicrophoneInfo} by device information while filtering certain types.
6892 */
6893 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6894 HashSet<Integer> filterTypes) {
6895 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6896 for (AudioDeviceInfo device : devices) {
6897 if (filterTypes.contains(device.getType())) {
6898 continue;
6899 }
6900 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6901 microphones.add(microphone);
6902 }
6903 }
6904
6905 /**
jiabinc0f49442018-01-05 10:23:50 -08006906 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6907 * of all available microphones. The list is empty when no microphones are available
6908 * on the device. An error during the query will result in an IOException being thrown.
6909 *
6910 * @return a list that contains all microphones' characteristics
6911 * @throws IOException if an error occurs.
6912 */
6913 public List<MicrophoneInfo> getMicrophones() throws IOException {
6914 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6915 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006916 HashSet<Integer> filterTypes = new HashSet<>();
6917 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08006918 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07006919 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07006920 if (status != AudioManager.ERROR_INVALID_OPERATION) {
6921 Log.e(TAG, "getMicrophones failed:" + status);
6922 }
6923 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07006924 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6925 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08006926 }
6927 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006928 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6929 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08006930 return microphones;
6931 }
6932
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006933 /**
6934 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01006935 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006936 *
6937 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01006938 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006939 * @hide
6940 */
William Escandea05cb452021-12-08 14:14:19 +01006941 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6942 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
6943 ArrayList<Integer> formatsList = new ArrayList<>();
6944 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006945
William Escandea05cb452021-12-08 14:14:19 +01006946 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
6947 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006948 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01006949 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
6950 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006951 }
6952
William Escandea05cb452021-12-08 14:14:19 +01006953 for (Integer format : formatsList) {
6954 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6955 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6956 codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006957 }
William Escandea05cb452021-12-08 14:14:19 +01006958 }
6959 return codecConfigList;
6960 }
6961
6962 /**
6963 * Returns a list of audio formats that corresponds to encoding formats
6964 * supported on offload path for Le audio playback.
6965 *
6966 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
6967 * supported for offload Le Audio playback
6968 * @hide
6969 */
6970 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6971 @NonNull
6972 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
6973 ArrayList<Integer> formatsList = new ArrayList<>();
6974 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
6975
6976 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
6977 AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
6978 if (status != AudioManager.SUCCESS) {
6979 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08006980 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006981 }
William Escandea05cb452021-12-08 14:14:19 +01006982
6983 for (Integer format : formatsList) {
6984 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
6985 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6986 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
6987 .setCodecType(btLeAudioCodec)
6988 .build());
6989 }
6990 }
6991 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006992 }
6993
Paul McLeancbeb8a22015-06-10 08:21:27 -07006994 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
6995 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
6996 // of the ports that exist at the time of the last notification.
6997 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
6998
Paul McLeane3383cc2015-05-08 11:41:20 -07006999 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007000 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07007001 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07007002 */
jiabin8c3a7672018-05-22 15:44:21 -07007003 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07007004 int status;
7005
Paul McLeancbeb8a22015-06-10 08:21:27 -07007006 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07007007 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
7008 status = AudioManager.listAudioDevicePorts(current_ports);
7009 if (status != AudioManager.SUCCESS) {
7010 return;
7011 }
7012
Paul McLeancbeb8a22015-06-10 08:21:27 -07007013 if (handler != null) {
7014 // This is the callback for the registration, so send the current list
7015 AudioDeviceInfo[] deviceList =
7016 infoListFromPortList(current_ports, GET_DEVICES_ALL);
7017 handler.sendMessage(
7018 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
7019 } else {
7020 AudioDeviceInfo[] added_devices =
7021 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
7022 AudioDeviceInfo[] removed_devices =
7023 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07007024 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07007025 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
7026 handler = mDeviceCallbacks.valueAt(i).getHandler();
7027 if (handler != null) {
7028 if (removed_devices.length != 0) {
7029 handler.sendMessage(Message.obtain(handler,
7030 MSG_DEVICES_DEVICES_REMOVED,
7031 removed_devices));
7032 }
7033 if (added_devices.length != 0) {
7034 handler.sendMessage(Message.obtain(handler,
7035 MSG_DEVICES_DEVICES_ADDED,
7036 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07007037 }
Paul McLean03346882015-05-12 15:36:56 -07007038 }
7039 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007040 }
7041 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007042
7043 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07007044 }
7045
7046 /**
7047 * Handles Port list update notifications from the AudioManager
7048 */
7049 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
7050 static final String TAG = "OnAmPortUpdateListener";
7051 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07007052 synchronized (mDeviceCallbacks) {
7053 broadcastDeviceListChange_sync(null);
7054 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007055 }
7056
7057 /**
7058 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007059 * Note: We don't do anything with Patches at this time, so ignore this notification.
7060 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07007061 */
7062 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
7063
7064 /**
7065 * Callback method called when the mediaserver dies
7066 */
7067 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07007068 synchronized (mDeviceCallbacks) {
7069 broadcastDeviceListChange_sync(null);
7070 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007071 }
7072 }
7073
Eric Laurent1d3cdce2018-01-20 10:31:21 -08007074
7075 /**
7076 * @hide
7077 * Abstract class to receive event notification about audioserver process state.
7078 */
7079 @SystemApi
7080 public abstract static class AudioServerStateCallback {
7081 public void onAudioServerDown() { }
7082 public void onAudioServerUp() { }
7083 }
7084
7085 private Executor mAudioServerStateExec;
7086 private AudioServerStateCallback mAudioServerStateCb;
7087 private final Object mAudioServerStateCbLock = new Object();
7088
7089 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
7090 new IAudioServerStateDispatcher.Stub() {
7091 @Override
7092 public void dispatchAudioServerStateChange(boolean state) {
7093 Executor exec;
7094 AudioServerStateCallback cb;
7095
7096 synchronized (mAudioServerStateCbLock) {
7097 exec = mAudioServerStateExec;
7098 cb = mAudioServerStateCb;
7099 }
7100
7101 if ((exec == null) || (cb == null)) {
7102 return;
7103 }
7104 if (state) {
7105 exec.execute(() -> cb.onAudioServerUp());
7106 } else {
7107 exec.execute(() -> cb.onAudioServerDown());
7108 }
7109 }
7110 };
7111
7112 /**
7113 * @hide
7114 * Registers a callback for notification of audio server state changes.
7115 * @param executor {@link Executor} to handle the callbacks
7116 * @param stateCallback the callback to receive the audio server state changes
7117 * To remove the callabck, pass a null reference for both executor and stateCallback.
7118 */
7119 @SystemApi
7120 public void setAudioServerStateCallback(@NonNull Executor executor,
7121 @NonNull AudioServerStateCallback stateCallback) {
7122 if (stateCallback == null) {
7123 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
7124 }
7125 if (executor == null) {
7126 throw new IllegalArgumentException(
7127 "Illegal null Executor for the AudioServerStateCallback");
7128 }
7129
7130 synchronized (mAudioServerStateCbLock) {
7131 if (mAudioServerStateCb != null) {
7132 throw new IllegalStateException(
7133 "setAudioServerStateCallback called with already registered callabck");
7134 }
7135 final IAudioService service = getService();
7136 try {
7137 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7138 } catch (RemoteException e) {
7139 throw e.rethrowFromSystemServer();
7140 }
7141 mAudioServerStateExec = executor;
7142 mAudioServerStateCb = stateCallback;
7143 }
7144 }
7145
7146 /**
7147 * @hide
7148 * Unregisters the callback for notification of audio server state changes.
7149 */
7150 @SystemApi
7151 public void clearAudioServerStateCallback() {
7152 synchronized (mAudioServerStateCbLock) {
7153 if (mAudioServerStateCb != null) {
7154 final IAudioService service = getService();
7155 try {
7156 service.unregisterAudioServerStateDispatcher(
7157 mAudioServerStateDispatcher);
7158 } catch (RemoteException e) {
7159 throw e.rethrowFromSystemServer();
7160 }
7161 }
7162 mAudioServerStateExec = null;
7163 mAudioServerStateCb = null;
7164 }
7165 }
7166
7167 /**
7168 * @hide
7169 * Checks if native audioservice is running or not.
7170 * @return true if native audioservice runs, false otherwise.
7171 */
7172 @SystemApi
7173 public boolean isAudioServerRunning() {
7174 final IAudioService service = getService();
7175 try {
7176 return service.isAudioServerRunning();
7177 } catch (RemoteException e) {
7178 throw e.rethrowFromSystemServer();
7179 }
7180 }
7181
jiabin39940752018-04-02 18:18:45 -07007182 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007183 * Sets the surround sound mode.
7184 *
7185 * @return true if successful, otherwise false
7186 */
7187 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
7188 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7189 try {
7190 return getService().setEncodedSurroundMode(mode);
7191 } catch (RemoteException e) {
7192 throw e.rethrowFromSystemServer();
7193 }
7194 }
7195
7196 /**
7197 * Gets the surround sound mode.
7198 *
7199 * @return true if successful, otherwise false
7200 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007201 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7202 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007203 return getService().getEncodedSurroundMode(
7204 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007205 } catch (RemoteException e) {
7206 throw e.rethrowFromSystemServer();
7207 }
7208 }
7209
7210 /**
jiabin39940752018-04-02 18:18:45 -07007211 * @hide
7212 * Returns all surround formats.
7213 * @return a map where the key is a surround format and
7214 * the value indicates the surround format is enabled or not
7215 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007216 @TestApi
7217 @NonNull
jiabin39940752018-04-02 18:18:45 -07007218 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007219 try {
7220 return getService().getSurroundFormats();
7221 } catch (RemoteException e) {
7222 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007223 }
jiabin39940752018-04-02 18:18:45 -07007224 }
7225
7226 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007227 * Sets and persists a certain surround format as enabled or not.
7228 * <p>
7229 * This API is called by TvSettings surround sound menu when user enables or disables a
7230 * surround sound format. This setting is persisted as global user setting.
7231 * Applications should revert their changes to surround sound settings unless they intend to
7232 * modify the global user settings across all apps. The framework does not auto-revert an
7233 * application's settings after a lifecycle event. Audio focus is not required to apply these
7234 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007235 *
jiabin39940752018-04-02 18:18:45 -07007236 * @param enabled the required surround format state, true for enabled, false for disabled
7237 * @return true if successful, otherwise false
7238 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007239 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007240 public boolean setSurroundFormatEnabled(
7241 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007242 try {
7243 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7244 } catch (RemoteException e) {
7245 throw e.rethrowFromSystemServer();
7246 }
7247 }
7248
7249 /**
7250 * Gets whether a certain surround format is enabled or not.
7251 * @param audioFormat a surround format
7252 *
7253 * @return whether the required surround format is enabled
7254 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007255 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7256 try {
7257 return getService().isSurroundFormatEnabled(audioFormat);
7258 } catch (RemoteException e) {
7259 throw e.rethrowFromSystemServer();
7260 }
jiabin39940752018-04-02 18:18:45 -07007261 }
7262
7263 /**
7264 * @hide
7265 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007266 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007267 *
Kriti Dang01924232021-03-02 13:51:09 +01007268 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007269 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007270 @TestApi
7271 @NonNull
7272 public List<Integer> getReportedSurroundFormats() {
7273 try {
7274 return getService().getReportedSurroundFormats();
7275 } catch (RemoteException e) {
7276 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007277 }
jiabin39940752018-04-02 18:18:45 -07007278 }
7279
jiabin66f9e722018-11-02 16:20:19 -07007280 /**
7281 * Return if audio haptic coupled playback is supported or not.
7282 *
7283 * @return whether audio haptic playback supported.
7284 */
7285 public static boolean isHapticPlaybackSupported() {
7286 return AudioSystem.isHapticPlaybackSupported();
7287 }
7288
François Gaffie0699fec2018-07-09 14:35:10 +02007289 /**
7290 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08007291 * Indicates whether a platform supports the Ultrasound feature which covers the playback
7292 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
7293 * usage will be
7294 * To start the Ultrasound playback:
7295 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
7296 * To start the Ultrasound capture:
7297 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
7298 *
7299 * @return whether the ultrasound feature is supported, true when platform supports both
7300 * Ultrasound playback and capture, false otherwise.
7301 */
7302 @SystemApi
Carter Hsu3ea30de42022-02-15 15:59:00 +08007303 @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
7304 public boolean isUltrasoundSupported() {
7305 try {
7306 return getService().isUltrasoundSupported();
7307 } catch (RemoteException e) {
7308 throw e.rethrowFromSystemServer();
7309 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08007310 }
7311
7312 /**
7313 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02007314 * Introspection API to retrieve audio product strategies.
7315 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7316 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7317 * by OEM without any needs of AOSP patches.
7318 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7319 * strategy refered either by its index or human readable string. It will allow clients
7320 * application to start streaming data using these {@link AudioAttributes} on the selected
7321 * device by Audio Policy Engine.
7322 * @return a (possibly zero-length) array of
7323 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7324 */
7325 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007326 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007327 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007328 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007329 final IAudioService service = getService();
7330 try {
7331 return service.getAudioProductStrategies();
7332 } catch (RemoteException e) {
7333 throw e.rethrowFromSystemServer();
7334 }
7335 }
7336
François Gaffieadcd00a2018-09-18 17:06:26 +02007337 /**
7338 * @hide
7339 * Introspection API to retrieve audio volume groups.
7340 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7341 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007342 * @return a (possibly zero-length) List of
7343 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007344 */
7345 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007346 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007347 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007348 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007349 final IAudioService service = getService();
7350 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007351 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007352 } catch (RemoteException e) {
7353 throw e.rethrowFromSystemServer();
7354 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007355 }
7356
7357 /**
7358 * @hide
7359 * Callback registered by client to be notified upon volume group change.
7360 */
7361 @SystemApi
7362 public abstract static class VolumeGroupCallback {
7363 /**
7364 * Callback method called upon audio volume group change.
7365 * @param group the group for which the volume has changed
7366 */
7367 public void onAudioVolumeGroupChanged(int group, int flags) {}
7368 }
7369
7370 /**
7371 * @hide
7372 * Register an audio volume group change listener.
7373 * @param callback the {@link VolumeGroupCallback} to register
7374 */
7375 @SystemApi
7376 public void registerVolumeGroupCallback(
7377 @NonNull Executor executor,
7378 @NonNull VolumeGroupCallback callback) {
7379 Preconditions.checkNotNull(executor, "executor must not be null");
7380 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7381 sAudioAudioVolumeGroupChangedHandler.init();
7382 // TODO: make use of executor
7383 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7384 }
7385
7386 /**
7387 * @hide
7388 * Unregister an audio volume group change listener.
7389 * @param callback the {@link VolumeGroupCallback} to unregister
7390 */
7391 @SystemApi
7392 public void unregisterVolumeGroupCallback(
7393 @NonNull VolumeGroupCallback callback) {
7394 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7395 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7396 }
jiabin39940752018-04-02 18:18:45 -07007397
jiabinad225202019-03-20 15:22:50 -07007398 /**
7399 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007400 *
7401 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007402 * @param uri the {@link Uri} of the asset.
7403 * @return true if the assert contains haptic channels.
7404 * @hide
7405 */
jiabincfcf1032021-07-01 16:30:50 -07007406 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7407 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007408 try {
jiabincfcf1032021-07-01 16:30:50 -07007409 extractor.setDataSource(context, uri, null);
7410 for (int i = 0; i < extractor.getTrackCount(); i++) {
7411 MediaFormat format = extractor.getTrackFormat(i);
7412 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7413 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7414 return true;
7415 }
7416 }
7417 } catch (IOException e) {
7418 Log.e(TAG, "hasHapticChannels failure:" + e);
7419 }
7420 return false;
7421 }
7422
7423 /**
7424 * Return if an asset contains haptic channels or not.
7425 *
7426 * @param context the {@link Context} to resolve the uri.
7427 * @param uri the {@link Uri} of the asset.
7428 * @return true if the assert contains haptic channels.
7429 * @hide
7430 */
7431 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7432 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07007433
jiabincfcf1032021-07-01 16:30:50 -07007434 if (context != null) {
7435 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07007436 }
7437
7438 Context cachedContext = sContext.get();
7439 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07007440 if (DEBUG) {
7441 Log.d(TAG, "Try to use static context to query if having haptic channels");
7442 }
jiabin0f3339c2021-07-09 11:50:07 -07007443 return hasHapticChannelsImpl(cachedContext, uri);
7444 }
7445
7446 // Try with audio service context, this may fail to get correct result.
7447 if (DEBUG) {
7448 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7449 }
7450 try {
7451 return getService().hasHapticChannels(uri);
7452 } catch (RemoteException e) {
7453 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07007454 }
7455 }
7456
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007457 /**
7458 * Set whether or not there is an active RTT call.
7459 * This method should be called by Telecom service.
7460 * @hide
7461 * TODO: make this a @SystemApi
7462 */
7463 public static void setRttEnabled(boolean rttEnabled) {
7464 try {
7465 getService().setRttEnabled(rttEnabled);
7466 } catch (RemoteException e) {
7467 throw e.rethrowFromSystemServer();
7468 }
7469 }
7470
Jin Seok Park16aeba382020-08-06 12:52:54 +09007471 /**
7472 * Adjusts the volume of the most relevant stream, or the given fallback
7473 * stream.
7474 * <p>
7475 * This method should only be used by applications that replace the
7476 * platform-wide management of audio settings or the main telephony
7477 * application.
7478 * <p>
7479 * This method has no effect if the device implements a fixed volume policy
7480 * as indicated by {@link #isVolumeFixed()}.
7481 * <p>This API checks if the caller has the necessary permissions based on the provided
7482 * component name, uid, and pid values.
7483 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7484 *
7485 * @param suggestedStreamType The stream type that will be used if there
7486 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7487 * valid here.
7488 * @param direction The direction to adjust the volume. One of
7489 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7490 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7491 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7492 * @param flags One or more flags.
7493 * @param packageName the package name of client application
7494 * @param uid the uid of client application
7495 * @param pid the pid of client application
7496 * @param targetSdkVersion the target sdk version of client application
7497 * @see #adjustVolume(int, int)
7498 * @see #adjustStreamVolume(int, int, int)
7499 * @see #setStreamVolume(int, int, int)
7500 * @see #isVolumeFixed()
7501 *
7502 * @hide
7503 */
7504 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7505 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7506 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7507 try {
7508 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7509 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7510 } catch (RemoteException e) {
7511 throw e.rethrowFromSystemServer();
7512 }
7513 }
7514
7515 /**
7516 * Adjusts the volume of a particular stream by one step in a direction.
7517 * <p>
7518 * This method should only be used by applications that replace the platform-wide
7519 * management of audio settings or the main telephony application.
7520 * <p>This method has no effect if the device implements a fixed volume policy
7521 * as indicated by {@link #isVolumeFixed()}.
7522 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7523 * unless the app has been granted Do Not Disturb Access.
7524 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7525 * <p>This API checks if the caller has the necessary permissions based on the provided
7526 * component name, uid, and pid values.
7527 * See {@link #adjustStreamVolume(int, int, int)}.
7528 *
7529 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7530 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7531 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7532 * @param direction The direction to adjust the volume. One of
7533 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7534 * {@link #ADJUST_SAME}.
7535 * @param flags One or more flags.
7536 * @param packageName the package name of client application
7537 * @param uid the uid of client application
7538 * @param pid the pid of client application
7539 * @param targetSdkVersion the target sdk version of client application
7540 * @see #adjustVolume(int, int)
7541 * @see #setStreamVolume(int, int, int)
7542 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7543 * and the caller is not granted notification policy access.
7544 *
7545 * @hide
7546 */
7547 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7548 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7549 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7550 try {
7551 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7552 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7553 } catch (RemoteException e) {
7554 throw e.rethrowFromSystemServer();
7555 }
7556 }
7557
7558 /**
7559 * Sets the volume index for a particular stream.
7560 * <p>This method has no effect if the device implements a fixed volume policy
7561 * as indicated by {@link #isVolumeFixed()}.
7562 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7563 * the app has been granted Do Not Disturb Access.
7564 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7565 * <p>This API checks if the caller has the necessary permissions based on the provided
7566 * component name, uid, and pid values.
7567 * See {@link #setStreamVolume(int, int, int)}.
7568 *
7569 * @param streamType The stream whose volume index should be set.
7570 * @param index The volume index to set. See
7571 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7572 * @param flags One or more flags.
7573 * @param packageName the package name of client application
7574 * @param uid the uid of client application
7575 * @param pid the pid of client application
7576 * @param targetSdkVersion the target sdk version of client application
7577 * @see #getStreamMaxVolume(int)
7578 * @see #getStreamVolume(int)
7579 * @see #isVolumeFixed()
7580 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7581 * and the caller is not granted notification policy access.
7582 *
7583 * @hide
7584 */
7585 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7586 public void setStreamVolumeForUid(int streamType, int index, int flags,
7587 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7588 try {
7589 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7590 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7591 } catch (RemoteException e) {
7592 throw e.rethrowFromSystemServer();
7593 }
7594 }
7595
7596
hjin81.lee4e984e52019-12-05 14:34:52 +09007597 /** @hide
7598 * TODO: make this a @SystemApi */
7599 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7600 public void setMultiAudioFocusEnabled(boolean enabled) {
7601 try {
7602 getService().setMultiAudioFocusEnabled(enabled);
7603 } catch (RemoteException e) {
7604 throw e.rethrowFromSystemServer();
7605 }
7606 }
7607
Eric Laurent43a78de2020-07-24 17:11:15 -07007608
7609 /**
7610 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7611 * For more details on Hardware A/V synchronization please refer to
7612 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7613 * media tunneling documentation</a>.
7614 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7615 * @return the HW A/V sync ID for this audio session (an integer different from 0).
7616 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7617 */
7618 public int getAudioHwSyncForSession(int sessionId) {
7619 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7620 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7621 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7622 }
7623 return hwSyncId;
7624 }
7625
Eric Laurentb36d4a12020-10-09 09:52:49 -07007626 /**
7627 * Selects the audio device that should be used for communication use cases, for instance voice
7628 * or video calls. This method can be used by voice or video chat applications to select a
7629 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01007630 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7631 * {@link #getAvailableCommunicationDevices()}.
7632 * The selection is active as long as the requesting application process lives, until
7633 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007634 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01007635 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007636 * <p>In case of simultaneous requests by multiple applications the priority is given to the
7637 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7638 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7639 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7640 * telephony application with permission
7641 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7642 * <p> If the requested devices is not currently available, the request will be rejected and
7643 * the method will return false.
7644 * <p>This API replaces the following deprecated APIs:
7645 * <ul>
7646 * <li> {@link #startBluetoothSco()}
7647 * <li> {@link #stopBluetoothSco()}
7648 * <li> {@link #setSpeakerphoneOn(boolean)}
7649 * </ul>
7650 * <h4>Example</h4>
7651 * <p>The example below shows how to enable and disable speakerphone mode.
7652 * <pre class="prettyprint">
7653 * // Get an AudioManager instance
7654 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01007655 * AudioDeviceInfo speakerDevice = null;
7656 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7657 * for (AudioDeviceInfo device : devices) {
7658 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7659 * speakerDevice = device;
7660 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007661 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007662 * }
7663 * if (speakerDevice != null) {
7664 * // Turn speakerphone ON.
7665 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
7666 * if (!result) {
7667 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007668 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007669 * // Turn speakerphone OFF.
7670 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007671 * }
7672 * </pre>
7673 * @param device the requested audio device.
7674 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7675 * @throws IllegalArgumentException If an invalid device is specified.
7676 */
Eric Laurent7412f572021-02-11 15:10:31 +01007677 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007678 Objects.requireNonNull(device);
7679 try {
7680 if (device.getId() == 0) {
7681 throw new IllegalArgumentException("In valid device: " + device);
7682 }
Eric Laurent7412f572021-02-11 15:10:31 +01007683 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007684 } catch (RemoteException e) {
7685 throw e.rethrowFromSystemServer();
7686 }
7687 }
7688
7689 /**
7690 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01007691 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007692 */
Eric Laurent7412f572021-02-11 15:10:31 +01007693 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007694 try {
Eric Laurent7412f572021-02-11 15:10:31 +01007695 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007696 } catch (RemoteException e) {
7697 throw e.rethrowFromSystemServer();
7698 }
7699 }
7700
7701 /**
7702 * Returns currently selected audio device for communication.
7703 * <p>This API replaces the following deprecated APIs:
7704 * <ul>
7705 * <li> {@link #isBluetoothScoOn()}
7706 * <li> {@link #isSpeakerphoneOn()}
7707 * </ul>
7708 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01007709 * currently selected for communication use cases. Can be null on platforms
7710 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007711 * is used.
7712 */
7713 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01007714 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007715 try {
7716 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01007717 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7718 } catch (RemoteException e) {
7719 throw e.rethrowFromSystemServer();
7720 }
7721 }
7722
7723 /**
7724 * Returns a list of audio devices that can be selected for communication use cases via
7725 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7726 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7727 */
7728 @NonNull
7729 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7730 try {
7731 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7732 int[] portIds = getService().getAvailableCommunicationDeviceIds();
7733 for (int portId : portIds) {
7734 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7735 if (device == null) {
7736 continue;
7737 }
7738 devices.add(device);
7739 }
7740 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007741 } catch (RemoteException e) {
7742 throw e.rethrowFromSystemServer();
7743 }
7744 }
7745
7746 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01007747 * Returns a list of direct {@link AudioProfile} that are supported for the specified
7748 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
7749 * is possible.
7750 *
7751 * <p>Direct playback means that the audio stream is not resampled or downmixed
7752 * by the framework. Checking for direct support can help the app select the representation
7753 * of audio content that most closely matches the capabilities of the device and peripherals
7754 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
7755 * or mixed with other streams, if needed.
7756 * <p>When using this information to inform your application which audio format to play,
7757 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
7758 * @param attributes a non-null {@link AudioAttributes} instance.
7759 * @return a list of {@link AudioProfile}
7760 */
7761 @NonNull
7762 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
7763 Objects.requireNonNull(attributes);
7764 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
7765 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
7766 if (status != SUCCESS) {
7767 Log.w(TAG, "getDirectProfilesForAttributes failed.");
7768 return new ArrayList<>();
7769 }
7770 return audioProfilesList;
7771 }
7772
7773 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007774 * @hide
7775 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7776 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7777 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7778 * The method will return null if no device of the provided type is connected.
7779 * If more than one device of the provided type is connected, an object corresponding to the
7780 * first device encountered in the enumeration list will be returned.
7781 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01007782 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007783 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7784 * @throws IllegalArgumentException If an invalid device type is specified.
7785 */
7786 @TestApi
7787 @Nullable
7788 public static AudioDeviceInfo getDeviceInfoFromType(
7789 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01007790 return getDeviceInfoFromTypeAndAddress(deviceType, null);
7791 }
7792
Eric Laurent78eef3a2021-11-09 16:10:42 +01007793 /**
Eric Laurent7412f572021-02-11 15:10:31 +01007794 * @hide
7795 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7796 * address provided.
7797 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7798 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7799 * If a null address is provided, the matching will happen on the type only.
7800 * The method will return null if no device of the provided type and address is connected.
7801 * If more than one device of the provided type is connected, an object corresponding to the
7802 * first device encountered in the enumeration list will be returned.
7803 * @param type The device device for which an <code>AudioDeviceInfo</code>
7804 * object is queried.
7805 * @param address The device address for which an <code>AudioDeviceInfo</code>
7806 * object is queried or null if requesting match on type only.
7807 * @return An AudioDeviceInfo object or null if no matching device is connected.
7808 * @throws IllegalArgumentException If an invalid device type is specified.
7809 */
7810 @Nullable
7811 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7812 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007813 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01007814 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007815 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01007816 if (device.getType() == type) {
7817 deviceForType = device;
7818 if (address == null || address.equals(device.getAddress())) {
7819 return device;
7820 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007821 }
7822 }
Eric Laurent7412f572021-02-11 15:10:31 +01007823 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007824 }
7825
7826 /**
7827 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007828 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007829 */
7830 public interface OnCommunicationDeviceChangedListener {
7831 /**
7832 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007833 * @param device the audio device requested for communication use cases.
7834 * Can be null on platforms not supporting
7835 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007836 */
7837 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7838 }
7839
7840 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007841 * manages the OnCommunicationDeviceChangedListener listeners and the
7842 * CommunicationDeviceDispatcherStub
7843 */
7844 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
7845 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
7846 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007847 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007848 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007849 * @param executor
7850 * @param listener
7851 */
7852 public void addOnCommunicationDeviceChangedListener(
7853 @NonNull @CallbackExecutor Executor executor,
7854 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007855 mCommDeviceChangedListenerMgr.addListener(
7856 executor, listener, "addOnCommunicationDeviceChangedListener",
7857 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007858 }
7859
7860 /**
7861 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007862 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007863 * @param listener
7864 */
7865 public void removeOnCommunicationDeviceChangedListener(
7866 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007867 mCommDeviceChangedListenerMgr.removeListener(listener,
7868 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07007869 }
7870
Eric Laurentb36d4a12020-10-09 09:52:49 -07007871 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007872 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007873
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007874 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007875 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007876 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007877 if (register) {
7878 getService().registerCommunicationDeviceDispatcher(this);
7879 } else {
7880 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007881 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007882 } catch (RemoteException e) {
7883 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007884 }
7885 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007886
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007887 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007888 public void dispatchCommunicationDeviceChanged(int portId) {
7889 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007890 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007891 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07007892 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007893 }
7894
Eric Laurent78eef3a2021-11-09 16:10:42 +01007895
7896 /**
7897 * @hide
7898 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
7899 * PSTN call.
7900 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
7901 * an AudioTrack for call uplink audio injection and
7902 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
7903 * an AudioRecord for call downlink audio extraction.
7904 * @return true if PSTN call audio is accessible, false otherwise.
7905 */
7906 @TestApi
7907 @SystemApi
7908 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
7909 public boolean isPstnCallAudioInterceptable() {
7910 final IAudioService service = getService();
7911 try {
7912 return service.isPstnCallAudioInterceptable();
7913 } catch (RemoteException e) {
7914 throw e.rethrowFromSystemServer();
7915 }
7916 }
7917
7918 /** @hide */
7919 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
7920 CALL_REDIRECT_NONE,
7921 CALL_REDIRECT_PSTN,
7922 CALL_REDIRECT_VOIP }
7923 )
7924 @Retention(RetentionPolicy.SOURCE)
7925 public @interface CallRedirectionMode {}
7926
7927 /**
7928 * Not used for call redirection
7929 * @hide
7930 */
7931 public static final int CALL_REDIRECT_NONE = 0;
7932 /**
7933 * Used to redirect PSTN call
7934 * @hide
7935 */
7936 public static final int CALL_REDIRECT_PSTN = 1;
7937 /**
7938 * Used to redirect VoIP call
7939 * @hide
7940 */
7941 public static final int CALL_REDIRECT_VOIP = 2;
7942
7943
7944 private @CallRedirectionMode int getCallRedirectMode() {
7945 int mode = getMode();
7946 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
7947 || mode == MODE_CALL_REDIRECT) {
7948 return CALL_REDIRECT_PSTN;
7949 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
7950 return CALL_REDIRECT_VOIP;
7951 }
7952 return CALL_REDIRECT_NONE;
7953 }
7954
7955 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
7956 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
7957 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
7958 throw new UnsupportedOperationException(" Unsupported encoding ");
7959 }
7960 if (format.getSampleRate() < 8000
7961 || format.getSampleRate() > 48000) {
7962 throw new UnsupportedOperationException(" Unsupported sample rate ");
7963 }
7964 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
7965 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
7966 throw new UnsupportedOperationException(" Unsupported output channel mask ");
7967 }
7968 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
7969 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
7970 throw new UnsupportedOperationException(" Unsupported input channel mask ");
7971 }
7972 }
7973
7974 class CallIRedirectionClientInfo {
7975 public WeakReference trackOrRecord;
7976 public int redirectMode;
7977 }
7978
7979 private Object mCallRedirectionLock = new Object();
7980 @GuardedBy("mCallRedirectionLock")
7981 private CallInjectionModeChangedListener mCallRedirectionModeListener;
7982 @GuardedBy("mCallRedirectionLock")
7983 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
7984
7985 /**
7986 * @hide
7987 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
7988 * This can be used for functions like call screening or call audio redirection and is reserved
7989 * to system apps with privileged permission.
7990 * @param format the desired audio format for audio playback.
7991 * p>Formats accepted are:
7992 * <ul>
7993 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
7994 * <li><em>Channel mask</em> - Mono or Stereo </li>
7995 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
7996 * </ul>
7997 *
7998 * @return The AudioTrack used for audio injection
7999 * @throws NullPointerException if AudioFormat argument is null.
8000 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8001 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8002 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8003 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8004 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8005 * or MODE_COMMUNICATION_REDIRECT.
8006 */
8007 @TestApi
8008 @SystemApi
8009 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8010 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
8011 Objects.requireNonNull(format);
8012 checkCallRedirectionFormat(format, true /* isOutput */);
8013
8014 AudioTrack track = null;
8015 int redirectMode = getCallRedirectMode();
8016 if (redirectMode == CALL_REDIRECT_NONE) {
8017 throw new IllegalStateException(
8018 " not available in mode " + AudioSystem.modeToString(getMode()));
8019 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8020 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8021 }
8022
8023 track = new AudioTrack.Builder()
8024 .setAudioAttributes(new AudioAttributes.Builder()
8025 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
8026 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
8027 .build())
8028 .setAudioFormat(format)
8029 .setCallRedirectionMode(redirectMode)
8030 .build();
8031
8032 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
8033 synchronized (mCallRedirectionLock) {
8034 if (mCallRedirectionModeListener == null) {
8035 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8036 try {
8037 addOnModeChangedListener(
8038 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8039 } catch (Exception e) {
8040 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8041 mCallRedirectionModeListener = null;
8042 throw new UnsupportedOperationException(" Cannot register mode listener ");
8043 }
8044 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8045 }
8046 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8047 info.redirectMode = redirectMode;
8048 info.trackOrRecord = new WeakReference<AudioTrack>(track);
8049 mCallIRedirectionClients.add(info);
8050 }
8051 } else {
8052 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
8053 }
8054 return track;
8055 }
8056
8057 /**
8058 * @hide
8059 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
8060 * This can be used for functions like call screening or call audio redirection and is reserved
8061 * to system apps with privileged permission.
8062 * @param format the desired audio format for audio capture.
8063 *<p>Formats accepted are:
8064 * <ul>
8065 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8066 * <li><em>Channel mask</em> - Mono or Stereo </li>
8067 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8068 * </ul>
8069 *
8070 * @return The AudioRecord used for audio extraction
8071 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8072 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8073 * @throws NullPointerException if AudioFormat argument is null.
8074 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8075 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8076 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8077 * or MODE_COMMUNICATION_REDIRECT.
8078 */
8079 @TestApi
8080 @SystemApi
8081 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8082 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
8083 Objects.requireNonNull(format);
8084 checkCallRedirectionFormat(format, false /* isOutput */);
8085
8086 AudioRecord record = null;
8087 int redirectMode = getCallRedirectMode();
8088 if (redirectMode == CALL_REDIRECT_NONE) {
8089 throw new IllegalStateException(
8090 " not available in mode " + AudioSystem.modeToString(getMode()));
8091 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8092 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8093 }
8094
8095 record = new AudioRecord.Builder()
8096 .setAudioAttributes(new AudioAttributes.Builder()
8097 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
8098 .build())
8099 .setAudioFormat(format)
8100 .setCallRedirectionMode(redirectMode)
8101 .build();
8102
8103 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
8104 synchronized (mCallRedirectionLock) {
8105 if (mCallRedirectionModeListener == null) {
8106 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8107 try {
8108 addOnModeChangedListener(
8109 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8110 } catch (Exception e) {
8111 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8112 mCallRedirectionModeListener = null;
8113 throw new UnsupportedOperationException(" Cannot register mode listener ");
8114 }
8115 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8116 }
8117 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8118 info.redirectMode = redirectMode;
8119 info.trackOrRecord = new WeakReference<AudioRecord>(record);
8120 mCallIRedirectionClients.add(info);
8121 }
8122 } else {
8123 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
8124 }
8125 return record;
8126 }
8127
8128 class CallInjectionModeChangedListener implements OnModeChangedListener {
8129 @Override
8130 public void onModeChanged(@AudioMode int mode) {
8131 synchronized (mCallRedirectionLock) {
8132 final ArrayList<CallIRedirectionClientInfo> clientInfos =
8133 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
8134 for (CallIRedirectionClientInfo info : clientInfos) {
8135 Object trackOrRecord = info.trackOrRecord.get();
8136 if (trackOrRecord != null) {
8137 if ((info.redirectMode == CALL_REDIRECT_PSTN
8138 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
8139 && mode != MODE_CALL_REDIRECT)
8140 || (info.redirectMode == CALL_REDIRECT_VOIP
8141 && mode != MODE_IN_COMMUNICATION
8142 && mode != MODE_COMMUNICATION_REDIRECT)) {
8143 if (trackOrRecord instanceof AudioTrack) {
8144 AudioTrack track = (AudioTrack) trackOrRecord;
8145 track.release();
8146 } else {
8147 AudioRecord record = (AudioRecord) trackOrRecord;
8148 record.release();
8149 }
8150 mCallIRedirectionClients.remove(info);
8151 }
8152 }
8153 }
8154 if (mCallIRedirectionClients.isEmpty()) {
8155 try {
8156 if (mCallRedirectionModeListener != null) {
8157 removeOnModeChangedListener(mCallRedirectionModeListener);
8158 }
8159 } catch (Exception e) {
8160 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
8161 } finally {
8162 mCallRedirectionModeListener = null;
8163 mCallIRedirectionClients = null;
8164 }
8165 }
8166 }
8167 }
8168 }
8169
Paul McLeane3383cc2015-05-08 11:41:20 -07008170 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008171 // audio device connection-dependent muting
8172 /**
8173 * @hide
8174 * Mute a set of playback use cases until a given audio device is connected.
8175 * Automatically unmute upon connection of the device, or after the given timeout, whichever
8176 * happens first.
8177 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
8178 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
8179 * device connects
8180 * @param device the audio device expected to connect within the timeout duration
8181 * @param timeout the maximum amount of time to wait for the device connection
8182 * @param timeUnit the unit for the timeout
8183 * @throws IllegalStateException when trying to issue the command while another is already in
8184 * progress and hasn't been cancelled by
8185 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8186 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8187 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8188 */
8189 @SystemApi
8190 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8191 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8192 @NonNull AudioDeviceAttributes device,
8193 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8194 if (timeout <= 0) {
8195 throw new IllegalArgumentException("Timeout must be greater than 0");
8196 }
8197 Objects.requireNonNull(usagesToMute);
8198 if (usagesToMute.length == 0) {
8199 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8200 }
8201 Objects.requireNonNull(device);
8202 Objects.requireNonNull(timeUnit);
8203 try {
8204 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8205 } catch (RemoteException e) {
8206 throw e.rethrowFromSystemServer();
8207 }
8208 }
8209
8210 /**
8211 * @hide
8212 * Query which audio device, if any, is causing some playback use cases to be muted until it
8213 * connects.
8214 * @return the audio device used in
8215 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8216 * if there is no active muting command (either because the muting command was not issued
8217 * or because it timed out)
8218 */
8219 @SystemApi
8220 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8221 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8222 try {
8223 return getService().getMutingExpectedDevice();
8224 } catch (RemoteException e) {
8225 throw e.rethrowFromSystemServer();
8226 }
8227 }
8228
8229 /**
8230 * @hide
8231 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8232 * command.
8233 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8234 * command was issued.
8235 * @throws IllegalStateException when trying to issue the command for a device whose connection
8236 * is not anticipated by a previous call to
8237 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8238 */
8239 @SystemApi
8240 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8241 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8242 throws IllegalStateException {
8243 Objects.requireNonNull(device);
8244 try {
8245 getService().cancelMuteAwaitConnection(device);
8246 } catch (RemoteException e) {
8247 throw e.rethrowFromSystemServer();
8248 }
8249 }
8250
8251 /**
8252 * @hide
8253 * A callback class to receive events about the muting and unmuting of playback use cases
8254 * conditional on the upcoming connection of an audio device.
8255 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8256 */
8257 @SystemApi
8258 public abstract static class MuteAwaitConnectionCallback {
8259
8260 /**
8261 * An event where the expected audio device connected
8262 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8263 */
8264 public static final int EVENT_CONNECTION = 1;
8265 /**
8266 * An event where the expected audio device failed connect before the timeout happened
8267 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8268 */
8269 public static final int EVENT_TIMEOUT = 2;
8270 /**
8271 * An event where the {@code muteAwaitConnection()} command
8272 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
8273 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8274 */
8275 public static final int EVENT_CANCEL = 3;
8276
8277 /** @hide */
8278 @IntDef(flag = false, prefix = "EVENT_", value = {
8279 EVENT_CONNECTION,
8280 EVENT_TIMEOUT,
8281 EVENT_CANCEL }
8282 )
8283 @Retention(RetentionPolicy.SOURCE)
8284 public @interface UnmuteEvent {}
8285
8286 /**
8287 * Called when a number of playback use cases are muted in response to a call to
8288 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
8289 * @param device the audio device whose connection is expected. Playback use cases are
8290 * unmuted when that device connects
8291 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
8292 * playback use cases.
8293 */
8294 public void onMutedUntilConnection(
8295 @NonNull AudioDeviceAttributes device,
8296 @NonNull int[] mutedUsages) {}
8297
8298 /**
8299 * Called when an event occurred that caused playback uses cases to be unmuted
8300 * @param unmuteEvent the nature of the event
8301 * @param device the device that was expected to connect
8302 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
8303 * the event occurred
8304 */
8305 public void onUnmutedEvent(
8306 @UnmuteEvent int unmuteEvent,
8307 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
8308 }
8309
8310
8311 /**
8312 * @hide
8313 * Register a callback to receive updates on the playback muting conditional on a specific
8314 * audio device connection.
8315 * @param executor the {@link Executor} handling the callback
8316 * @param callback the callback to register
8317 */
8318 @SystemApi
8319 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8320 public void registerMuteAwaitConnectionCallback(
8321 @NonNull @CallbackExecutor Executor executor,
8322 @NonNull MuteAwaitConnectionCallback callback) {
8323 synchronized (mMuteAwaitConnectionListenerLock) {
8324 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8325 MuteAwaitConnectionDispatcherStub> res =
8326 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
8327 executor, callback, mMuteAwaitConnectionListeners,
8328 mMuteAwaitConnDispatcherStub,
8329 () -> new MuteAwaitConnectionDispatcherStub(),
8330 stub -> stub.register(true));
8331 mMuteAwaitConnectionListeners = res.first;
8332 mMuteAwaitConnDispatcherStub = res.second;
8333 }
8334 }
8335
8336 /**
8337 * @hide
8338 * Unregister a previously registered callback for playback muting conditional on device
8339 * connection.
8340 * @param callback the callback to unregister
8341 */
8342 @SystemApi
8343 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8344 public void unregisterMuteAwaitConnectionCallback(
8345 @NonNull MuteAwaitConnectionCallback callback) {
8346 synchronized (mMuteAwaitConnectionListenerLock) {
8347 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8348 MuteAwaitConnectionDispatcherStub> res =
8349 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
8350 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
8351 stub -> stub.register(false));
8352 mMuteAwaitConnectionListeners = res.first;
8353 mMuteAwaitConnDispatcherStub = res.second;
8354 }
8355 }
8356
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008357 /**
8358 * Add UID's that can be considered as assistant.
8359 *
8360 * @param assistantUids UID's of the services that can be considered as assistant.
8361 *
8362 * @hide
8363 */
8364 @SystemApi
8365 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8366 public void addAssistantServicesUids(@NonNull List<Integer> assistantUids) {
8367 try {
8368 getService().addAssistantServicesUids(assistantUids.stream()
8369 .mapToInt(Integer::intValue).toArray());
8370 } catch (RemoteException e) {
8371 throw e.rethrowFromSystemServer();
8372 }
8373 }
8374
8375 /**
8376 * Remove UID's that can be considered as assistant.
8377 *
8378 * @param assistantUids UID'S of the services that should be remove.
8379 *
8380 * @hide
8381 */
8382 @SystemApi
8383 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8384 public void removeAssistantServicesUids(@NonNull List<Integer> assistantUids) {
8385 try {
8386 getService().removeAssistantServicesUids(assistantUids.stream()
8387 .mapToInt(Integer::intValue).toArray());
8388 } catch (RemoteException e) {
8389 throw e.rethrowFromSystemServer();
8390 }
8391 }
8392
8393 /**
8394 * Get the list of assistants UIDs that been added with the
8395 * {@link #addAssistantServicesUids(List)} (List)} and not yet removed with
8396 * {@link #removeAssistantServicesUids(List)}
8397 *
8398 * @return list of assistants UID's
8399 *
8400 * @hide
8401 */
8402 @SystemApi
8403 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8404 public @NonNull List<Integer> getAssistantServicesUids() {
8405 try {
8406 int[] uids = getService().getAssistantServicesUids();
8407 return Arrays.stream(uids).boxed().collect(Collectors.toList());
8408 } catch (RemoteException e) {
8409 throw e.rethrowFromSystemServer();
8410 }
8411 }
8412
8413 /**
8414 * Sets UID's that can be considered as active assistant. Calling the API with a new list will
8415 * overwrite previous list. If the list of UIDs is empty then no UID will be considered active.
8416 * In this manner calling the API with an empty list will remove all UID's previously set.
8417 *
8418 * @param assistantUids UID'S of the services that can be considered active assistant. Can be
8419 * an empty list, for this no UID will be considered active.
8420 *
8421 * <p> Note that during audio service crash reset and after boot up the list of active assistant
8422 * UID's will be reset to an empty list (i.e. no UID will be considered as an active assistant).
8423 * Just after user switch the list of active assistant will also reset to empty.
8424 *
8425 * @hide
8426 */
8427 @SystemApi
8428 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8429 public void setActiveAssistantServiceUids(@NonNull List<Integer> assistantUids) {
8430 try {
8431 getService().setActiveAssistantServiceUids(assistantUids.stream()
8432 .mapToInt(Integer::intValue).toArray());
8433 } catch (RemoteException e) {
8434 throw e.rethrowFromSystemServer();
8435 }
8436 }
8437
8438 /**
8439 * Get the list of active assistant UIDs last set with the
8440 * {@link #setActiveAssistantServiceUids(List)}
8441 *
8442 * @return list of active assistants UID's
8443 *
8444 * @hide
8445 */
8446 @SystemApi
8447 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8448 public @NonNull List<Integer> getActiveAssistantServicesUids() {
8449 try {
8450 int[] uids = getService().getActiveAssistantServiceUids();
8451 return Arrays.stream(uids).boxed().collect(Collectors.toList());
8452 } catch (RemoteException e) {
8453 throw e.rethrowFromSystemServer();
8454 }
8455 }
8456
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008457 private final Object mMuteAwaitConnectionListenerLock = new Object();
8458
8459 @GuardedBy("mMuteAwaitConnectionListenerLock")
8460 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
8461 mMuteAwaitConnectionListeners;
8462
8463 @GuardedBy("mMuteAwaitConnectionListenerLock")
8464 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
8465
8466 private final class MuteAwaitConnectionDispatcherStub
8467 extends IMuteAwaitConnectionCallback.Stub {
8468 public void register(boolean register) {
8469 try {
8470 getService().registerMuteAwaitConnectionDispatcher(this, register);
8471 } catch (RemoteException e) {
8472 throw e.rethrowFromSystemServer();
8473 }
8474 }
8475
8476 @Override
8477 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8478 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
8479 int[] mutedUsages) {
8480 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8481 mMuteAwaitConnectionListenerLock,
8482 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
8483 }
8484
8485 @Override
8486 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8487 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
8488 int[] mutedUsages) {
8489 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8490 mMuteAwaitConnectionListenerLock,
8491 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
8492 }
8493 }
8494
8495 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07008496 // Inner classes
8497 //--------------------
8498 /**
8499 * Helper class to handle the forwarding of native events to the appropriate listener
8500 * (potentially) handled in a different thread.
8501 */
8502 private class NativeEventHandlerDelegate {
8503 private final Handler mHandler;
8504
Paul McLean03346882015-05-12 15:36:56 -07008505 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07008506 Handler handler) {
8507 // find the looper for our new event handler
8508 Looper looper;
8509 if (handler != null) {
8510 looper = handler.getLooper();
8511 } else {
8512 // no given handler, use the looper the addListener call was called in
8513 looper = Looper.getMainLooper();
8514 }
8515
8516 // construct the event handler with this looper
8517 if (looper != null) {
8518 // implement the event handler delegate
8519 mHandler = new Handler(looper) {
8520 @Override
8521 public void handleMessage(Message msg) {
8522 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07008523 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07008524 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07008525 if (callback != null) {
8526 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07008527 }
8528 break;
Paul McLean03346882015-05-12 15:36:56 -07008529
8530 case MSG_DEVICES_DEVICES_REMOVED:
8531 if (callback != null) {
8532 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
8533 }
8534 break;
8535
Paul McLeane3383cc2015-05-08 11:41:20 -07008536 default:
8537 Log.e(TAG, "Unknown native event type: " + msg.what);
8538 break;
8539 }
8540 }
8541 };
8542 } else {
8543 mHandler = null;
8544 }
8545 }
8546
8547 Handler getHandler() {
8548 return mHandler;
8549 }
8550 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08008551}