blob: c3e605e396f3d82034e41504de74105bd44597b7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080019import android.annotation.CallbackExecutor;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080020import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070021import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080022import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070023import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.annotation.SdkConstant;
26import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070027import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090028import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060029import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070030import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050031import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070032import android.app.PendingIntent;
Eric Laurent1c3408f2021-11-09 12:09:54 +010033import android.app.compat.CompatChanges;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080034import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070035import android.bluetooth.BluetoothDevice;
Patty46694212021-11-04 21:03:32 +080036import android.bluetooth.BluetoothLeAudioCodecConfig;
Eric Laurent1c3408f2021-11-09 12:09:54 +010037import android.compat.annotation.ChangeId;
38import android.compat.annotation.EnabledSince;
Artur Satayev53fe9662019-12-10 17:47:55 +000039import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070040import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070042import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080043import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080044import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070045import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080046import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070047import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070048import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020049import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080050import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070051import android.media.session.MediaController;
52import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070053import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070054import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070055import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070057import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Handler;
59import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080060import android.os.Looper;
61import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.os.RemoteException;
63import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050064import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010065import android.os.UserHandle;
Lais Andrade724d0cd2021-11-03 19:46:21 +000066import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080067import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070068import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080070import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070071import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080073import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020074import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080075
jiabinc0f49442018-01-05 10:23:50 -080076import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080077import java.lang.annotation.Retention;
78import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070079import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080080import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070081import java.util.Arrays;
Dorin Drimusdaeb6a92021-12-22 11:46:26 +010082import java.util.Collections;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080083import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070084import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090085import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080086import java.util.List;
jiabin39940752018-04-02 18:18:45 -070087import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070088import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090089import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070090import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080091import java.util.concurrent.Executor;
Eric Laurent78eef3a2021-11-09 16:10:42 +010092import java.util.concurrent.Executors;
Jean-Michel Trivi933bf142021-11-19 16:18:52 -080093import java.util.concurrent.TimeUnit;
Eric Laurent700e7342014-05-02 18:33:15 -070094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095/**
96 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060098@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099public class AudioManager {
100
Marco Nelissen29f16932015-04-17 09:50:56 -0700101 private Context mOriginalContext;
102 private Context mApplicationContext;
Joe Onorato86f67862010-11-05 18:57:34 -0700103 private long mVolumeKeyUpTime;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800104 private static final String TAG = "AudioManager";
105 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800106 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200107 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
108 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
jiabin0f3339c2021-07-09 11:50:07 -0700110 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 /**
113 * Broadcast intent, a hint for applications that audio is about to become
114 * 'noisy' due to a change in audio outputs. For example, this intent may
115 * be sent when a wired headset is unplugged, or when an A2DP audio
116 * sink is disconnected, and the audio system is about to automatically
117 * switch audio route to the speaker. Applications that are controlling
118 * audio streams may consider pausing, reducing volume or some other action
119 * on receipt of this intent so as not to surprise the user with audio
120 * from the speaker.
121 */
122 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
123 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
124
125 /**
126 * Sticky broadcast intent action indicating that the ringer mode has
127 * changed. Includes the new ringer mode.
128 *
129 * @see #EXTRA_RINGER_MODE
130 */
131 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
132 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
133
134 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500135 * @hide
136 * Sticky broadcast intent action indicating that the internal ringer mode has
137 * changed. Includes the new ringer mode.
138 *
139 * @see #EXTRA_RINGER_MODE
140 */
141 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
142 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
143 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
144
145 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 * The new ringer mode.
147 *
148 * @see #RINGER_MODE_CHANGED_ACTION
149 * @see #RINGER_MODE_NORMAL
150 * @see #RINGER_MODE_SILENT
151 * @see #RINGER_MODE_VIBRATE
152 */
153 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
154
155 /**
156 * Broadcast intent action indicating that the vibrate setting has
157 * changed. Includes the vibrate type and its new setting.
158 *
159 * @see #EXTRA_VIBRATE_TYPE
160 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700161 * @deprecated Applications should maintain their own vibrate policy based on
162 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 */
164 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500165 public static final String VIBRATE_SETTING_CHANGED_ACTION =
166 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
168 /**
169 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700170 * Includes the stream, the new volume and previous volumes.
171 * Notes:
172 * - for internal platform use only, do not make public,
173 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 *
175 * @see #EXTRA_VOLUME_STREAM_TYPE
176 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800177 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 */
179 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100180 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
182
183 /**
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800184 * @hide Broadcast intent when the volume for a particular stream type changes.
185 * Includes the stream, the new volume and previous volumes.
186 * Notes:
187 * - for internal platform use only, do not make public,
188 * - never used for "remote" volume changes
189 *
190 * @see #EXTRA_VOLUME_STREAM_TYPE
191 * @see #EXTRA_VOLUME_STREAM_VALUE
192 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
193 */
194 @SystemApi
195 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
196 @SuppressLint("ActionValue")
197 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
198
199 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400200 * @hide Broadcast intent when the devices for a particular stream type changes.
201 * Includes the stream, the new devices and previous devices.
202 * Notes:
203 * - for internal platform use only, do not make public,
204 * - never used for "remote" volume changes
205 *
206 * @see #EXTRA_VOLUME_STREAM_TYPE
207 * @see #EXTRA_VOLUME_STREAM_DEVICES
208 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
209 * @see #getDevicesForStream
210 */
211 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
212 public static final String STREAM_DEVICES_CHANGED_ACTION =
213 "android.media.STREAM_DEVICES_CHANGED_ACTION";
214
215 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800216 * @hide Broadcast intent when a stream mute state changes.
217 * Includes the stream that changed and the new mute state
218 *
219 * @see #EXTRA_VOLUME_STREAM_TYPE
220 * @see #EXTRA_STREAM_VOLUME_MUTED
221 */
222 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
223 public static final String STREAM_MUTE_CHANGED_ACTION =
224 "android.media.STREAM_MUTE_CHANGED_ACTION";
225
226 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500227 * @hide Broadcast intent when the master mute state changes.
228 * Includes the the new volume
229 *
230 * @see #EXTRA_MASTER_VOLUME_MUTED
231 */
232 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
233 public static final String MASTER_MUTE_CHANGED_ACTION =
234 "android.media.MASTER_MUTE_CHANGED_ACTION";
235
236 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 * The new vibrate setting for a particular type.
238 *
239 * @see #VIBRATE_SETTING_CHANGED_ACTION
240 * @see #EXTRA_VIBRATE_TYPE
241 * @see #VIBRATE_SETTING_ON
242 * @see #VIBRATE_SETTING_OFF
243 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700244 * @deprecated Applications should maintain their own vibrate policy based on
245 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 */
247 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
248
249 /**
250 * The vibrate type whose setting has changed.
251 *
252 * @see #VIBRATE_SETTING_CHANGED_ACTION
253 * @see #VIBRATE_TYPE_NOTIFICATION
254 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700255 * @deprecated Applications should maintain their own vibrate policy based on
256 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 */
258 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
259
260 /**
261 * @hide The stream type for the volume changed intent.
262 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800263 @SystemApi
264 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
266
267 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700268 * @hide
269 * The stream type alias for the volume changed intent.
270 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
271 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
272 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
273 * {@link #STREAM_MUSIC} on others (e.g. a television).
274 */
275 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
276 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
277
278 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 * @hide The volume associated with the stream for the volume changed intent.
280 */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800281 @SystemApi
282 @SuppressLint("ActionValue")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 public static final String EXTRA_VOLUME_STREAM_VALUE =
284 "android.media.EXTRA_VOLUME_STREAM_VALUE";
285
Eric Laurent9ce379a2010-02-16 06:00:26 -0800286 /**
287 * @hide The previous volume associated with the stream for the volume changed intent.
288 */
289 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
290 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
291
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500292 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400293 * @hide The devices associated with the stream for the stream devices changed intent.
294 */
295 public static final String EXTRA_VOLUME_STREAM_DEVICES =
296 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
297
298 /**
299 * @hide The previous devices associated with the stream for the stream devices changed intent.
300 */
301 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
302 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
303
304 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500305 * @hide The new master volume mute state for the master mute changed intent.
306 * Value is boolean
307 */
308 public static final String EXTRA_MASTER_VOLUME_MUTED =
309 "android.media.EXTRA_MASTER_VOLUME_MUTED";
310
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700311 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800312 * @hide The new stream volume mute state for the stream mute changed intent.
313 * Value is boolean
314 */
315 public static final String EXTRA_STREAM_VOLUME_MUTED =
316 "android.media.EXTRA_STREAM_VOLUME_MUTED";
317
318 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700319 * Broadcast Action: Wired Headset plugged in or unplugged.
320 *
321 * You <em>cannot</em> receive this through components declared
322 * in manifests, only by explicitly registering for it with
323 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
324 * Context.registerReceiver()}.
325 *
326 * <p>The intent will have the following extra values:
327 * <ul>
328 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
329 * <li><em>name</em> - Headset type, human readable string </li>
330 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
331 * </ul>
332 * </ul>
333 */
334 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
335 public static final String ACTION_HEADSET_PLUG =
336 "android.intent.action.HEADSET_PLUG";
337
338 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200339 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700340 *
341 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
342 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
343 * <p>It can only be received by explicitly registering for it with
344 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
345 */
346 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
347 public static final String ACTION_HDMI_AUDIO_PLUG =
348 "android.media.action.HDMI_AUDIO_PLUG";
349
350 /**
351 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
352 * or unplugged.
353 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
354 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700355 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700356
357 /**
358 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
359 * supported by the HDMI device.
360 * The corresponding integer value is only available when the device is plugged in (as expressed
361 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
362 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700363 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700364
365 /**
366 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
367 * the connected HDMI device.
368 * The corresponding array of encoding values is only available when the device is plugged in
369 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
370 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
371 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
372 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700373 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700374
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700375 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700377 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700379 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700381 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700383 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700385 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700387 /** @hide Used to identify the volume of audio streams for phone calls when connected
388 * to bluetooth */
Roopa Sattirajuf2675c72022-01-27 21:31:35 -0800389 @SystemApi
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700391 /** @hide Used to identify the volume of audio streams for enforced system sounds
392 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100393 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700394 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700395 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700396 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700397 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
398 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100399 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700400 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800401 /** Used to identify the volume of audio streams for accessibility prompts */
402 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000403 /** @hide Used to identify the volume of audio streams for virtual assistant */
404 @SystemApi
405 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
406 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 /** Number of audio streams */
409 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700410 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 */
Eric Laurenta553c252009-07-17 12:17:14 -0700412 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413
Paul McLeand6f87c82021-03-31 13:02:41 -0600414 /** @hide */
415 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
416 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
417 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
418 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
419
420 /** @hide */
421 @TestApi
422 public static final int[] getPublicStreamTypes() {
423 return PUBLIC_STREAM_TYPES;
424 }
425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 /**
427 * Increase the ringer volume.
428 *
429 * @see #adjustVolume(int, int)
430 * @see #adjustStreamVolume(int, int, int)
431 */
432 public static final int ADJUST_RAISE = 1;
433
434 /**
435 * Decrease the ringer volume.
436 *
437 * @see #adjustVolume(int, int)
438 * @see #adjustStreamVolume(int, int, int)
439 */
440 public static final int ADJUST_LOWER = -1;
441
442 /**
443 * Maintain the previous ringer volume. This may be useful when needing to
444 * show the volume toast without actually modifying the volume.
445 *
446 * @see #adjustVolume(int, int)
447 * @see #adjustStreamVolume(int, int, int)
448 */
449 public static final int ADJUST_SAME = 0;
450
RoboErik4197cb62015-01-21 15:45:32 -0800451 /**
452 * Mute the volume. Has no effect if the stream is already muted.
453 *
454 * @see #adjustVolume(int, int)
455 * @see #adjustStreamVolume(int, int, int)
456 */
457 public static final int ADJUST_MUTE = -100;
458
459 /**
460 * Unmute the volume. Has no effect if the stream is not muted.
461 *
462 * @see #adjustVolume(int, int)
463 * @see #adjustStreamVolume(int, int, int)
464 */
465 public static final int ADJUST_UNMUTE = 100;
466
467 /**
468 * Toggle the mute state. If muted the stream will be unmuted. If not muted
469 * the stream will be muted.
470 *
471 * @see #adjustVolume(int, int)
472 * @see #adjustStreamVolume(int, int, int)
473 */
474 public static final int ADJUST_TOGGLE_MUTE = 101;
475
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700476 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800477 @IntDef(flag = false, prefix = "ADJUST", value = {
478 ADJUST_RAISE,
479 ADJUST_LOWER,
480 ADJUST_SAME,
481 ADJUST_MUTE,
482 ADJUST_UNMUTE,
483 ADJUST_TOGGLE_MUTE }
484 )
485 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800486 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800487
488 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700489 public static final String adjustToString(int adj) {
490 switch (adj) {
491 case ADJUST_RAISE: return "ADJUST_RAISE";
492 case ADJUST_LOWER: return "ADJUST_LOWER";
493 case ADJUST_SAME: return "ADJUST_SAME";
494 case ADJUST_MUTE: return "ADJUST_MUTE";
495 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
496 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
497 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
498 }
499 }
500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 // Flags should be powers of 2!
502
503 /**
504 * Show a toast containing the current volume.
505 *
506 * @see #adjustStreamVolume(int, int, int)
507 * @see #adjustVolume(int, int)
508 * @see #setStreamVolume(int, int, int)
509 * @see #setRingerMode(int)
510 */
511 public static final int FLAG_SHOW_UI = 1 << 0;
512
513 /**
514 * Whether to include ringer modes as possible options when changing volume.
515 * For example, if true and volume level is 0 and the volume is adjusted
516 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
517 * vibrate mode.
518 * <p>
519 * By default this is on for the ring stream. If this flag is included,
520 * this behavior will be present regardless of the stream type being
521 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700522 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 * @see #adjustVolume(int, int)
524 * @see #adjustStreamVolume(int, int, int)
525 */
526 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
527
528 /**
529 * Whether to play a sound when changing the volume.
530 * <p>
531 * If this is given to {@link #adjustVolume(int, int)} or
532 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
533 * in some cases (for example, the decided stream type is not
534 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
535 * downward).
536 *
537 * @see #adjustStreamVolume(int, int, int)
538 * @see #adjustVolume(int, int)
539 * @see #setStreamVolume(int, int, int)
540 */
541 public static final int FLAG_PLAY_SOUND = 1 << 2;
542
543 /**
544 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
545 * changing volume).
546 */
547 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
548
549 /**
550 * Whether to vibrate if going into the vibrate ringer mode.
551 */
552 public static final int FLAG_VIBRATE = 1 << 4;
553
554 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700555 * Indicates to VolumePanel that the volume slider should be disabled as user
556 * cannot change the stream volume
557 * @hide
558 */
559 public static final int FLAG_FIXED_VOLUME = 1 << 5;
560
561 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700562 * Indicates the volume set/adjust call is for Bluetooth absolute volume
563 * @hide
564 */
Roopa Sattirajufb933242022-01-30 13:27:58 -0800565 @SystemApi
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700566 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
567
568 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400569 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
570 * @hide
571 */
572 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
573
574 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900575 * Indicates the volume call is for Hdmi Cec system audio volume
576 * @hide
577 */
578 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
579
580 /**
RoboErik3c45c292014-07-08 16:47:31 -0700581 * Indicates that this should only be handled if media is actively playing.
582 * @hide
583 */
584 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
585
586 /**
John Spurlock35134602014-07-24 18:10:48 -0400587 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
588 * @hide
589 */
590 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
591
592 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500593 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
594 * @hide
595 */
596 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
597
John Spurlockb94f2d62015-03-17 14:11:57 -0400598 /**
599 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900600 * This flag can be used in the places in order to denote (or check) that a volume adjustment
601 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400602 * @hide
603 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900604 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900605 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400606
Yan Han7d419822022-01-31 19:10:16 +0100607 /**
608 * Indicates that an absolute volume controller is notifying AudioService of a change in the
609 * volume or mute status of an external audio system.
610 * @hide
611 */
612 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
613
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900614 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100615 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200616 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100617 ENCODED_SURROUND_OUTPUT_AUTO,
618 ENCODED_SURROUND_OUTPUT_NEVER,
619 ENCODED_SURROUND_OUTPUT_ALWAYS,
620 ENCODED_SURROUND_OUTPUT_MANUAL
621 })
622 @Retention(RetentionPolicy.SOURCE)
623 public @interface EncodedSurroundOutputMode {}
624
625 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200626 * The mode for surround sound formats is unknown.
627 */
628 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
629
630 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100631 * The surround sound formats are available for use if they are detected. This is the default
632 * mode.
633 */
634 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
635
636 /**
637 * The surround sound formats are NEVER available, even if they are detected by the hardware.
638 * Those formats will not be reported.
639 */
640 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
641
642 /**
643 * The surround sound formats are ALWAYS available, even if they are not detected by the
644 * hardware. Those formats will be reported as part of the HDMI output capability.
645 * Applications are then free to use either PCM or encoded output.
646 */
647 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
648
649 /**
650 * Surround sound formats are available according to the choice of user, even if they are not
651 * detected by the hardware. Those formats will be reported as part of the HDMI output
652 * capability. Applications are then free to use either PCM or encoded output.
653 */
654 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
655
656 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900657 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900658 FLAG_SHOW_UI,
659 FLAG_ALLOW_RINGER_MODES,
660 FLAG_PLAY_SOUND,
661 FLAG_REMOVE_SOUND_AND_VIBRATE,
662 FLAG_VIBRATE,
663 FLAG_FIXED_VOLUME,
664 FLAG_BLUETOOTH_ABS_VOLUME,
665 FLAG_SHOW_SILENT_HINT,
666 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
667 FLAG_ACTIVE_MEDIA_ONLY,
668 FLAG_SHOW_UI_WARNINGS,
669 FLAG_SHOW_VIBRATE_HINT,
670 FLAG_FROM_KEY,
Yan Han7d419822022-01-31 19:10:16 +0100671 FLAG_ABSOLUTE_VOLUME,
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900672 })
673 @Retention(RetentionPolicy.SOURCE)
674 public @interface Flags {}
675
Hyundo Moonca0080d2018-12-26 16:16:55 +0900676 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
677 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
678
679 static {
680 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
681 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
682 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
683 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
684 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
685 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
686 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
687 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
688 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
689 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
690 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
691 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
692 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
Yan Han7d419822022-01-31 19:10:16 +0100693 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
Hyundo Moonca0080d2018-12-26 16:16:55 +0900694 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500695
696 /** @hide */
697 public static String flagsToString(int flags) {
698 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900699 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
700 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500701 if ((flags & flag) != 0) {
702 if (sb.length() > 0) {
703 sb.append(',');
704 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900705 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500706 flags &= ~flag;
707 }
708 }
709 if (flags != 0) {
710 if (sb.length() > 0) {
711 sb.append(',');
712 }
713 sb.append(flags);
714 }
715 return sb.toString();
716 }
717
718 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 * Ringer mode that will be silent and will not vibrate. (This overrides the
720 * vibrate setting.)
721 *
722 * @see #setRingerMode(int)
723 * @see #getRingerMode()
724 */
725 public static final int RINGER_MODE_SILENT = 0;
726
727 /**
728 * Ringer mode that will be silent and will vibrate. (This will cause the
729 * phone ringer to always vibrate, but the notification vibrate to only
730 * vibrate if set.)
731 *
732 * @see #setRingerMode(int)
733 * @see #getRingerMode()
734 */
735 public static final int RINGER_MODE_VIBRATE = 1;
736
737 /**
738 * Ringer mode that may be audible and may vibrate. It will be audible if
739 * the volume before changing out of this mode was audible. It will vibrate
740 * if the vibrate setting is on.
741 *
742 * @see #setRingerMode(int)
743 * @see #getRingerMode()
744 */
745 public static final int RINGER_MODE_NORMAL = 2;
746
John Spurlock97559372014-10-24 16:27:36 -0400747 /**
748 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
749 * @hide
750 */
751 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 /**
754 * Vibrate type that corresponds to the ringer.
755 *
756 * @see #setVibrateSetting(int, int)
757 * @see #getVibrateSetting(int)
758 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700759 * @deprecated Applications should maintain their own vibrate policy based on
760 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 */
762 public static final int VIBRATE_TYPE_RINGER = 0;
763
764 /**
765 * Vibrate type that corresponds to notifications.
766 *
767 * @see #setVibrateSetting(int, int)
768 * @see #getVibrateSetting(int)
769 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700770 * @deprecated Applications should maintain their own vibrate policy based on
771 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 */
773 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
774
775 /**
776 * Vibrate setting that suggests to never vibrate.
777 *
778 * @see #setVibrateSetting(int, int)
779 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700780 * @deprecated Applications should maintain their own vibrate policy based on
781 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 */
783 public static final int VIBRATE_SETTING_OFF = 0;
784
785 /**
786 * Vibrate setting that suggests to vibrate when possible.
787 *
788 * @see #setVibrateSetting(int, int)
789 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700790 * @deprecated Applications should maintain their own vibrate policy based on
791 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 */
793 public static final int VIBRATE_SETTING_ON = 1;
794
795 /**
796 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
797 * mode.
798 *
799 * @see #setVibrateSetting(int, int)
800 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700801 * @deprecated Applications should maintain their own vibrate policy based on
802 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 */
804 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
805
806 /**
807 * Suggests using the default stream type. This may not be used in all
808 * places a stream type is needed.
809 */
810 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
811
812 private static IAudioService sService;
813
814 /**
815 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800816 * For test purposes only, will throw NPE with some methods that require a Context.
817 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000818 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800819 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800820 }
821
822 /**
823 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100825 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700827 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
Marco Nelissen29f16932015-04-17 09:50:56 -0700830 private Context getContext() {
831 if (mApplicationContext == null) {
832 setContext(mOriginalContext);
833 }
834 if (mApplicationContext != null) {
835 return mApplicationContext;
836 }
837 return mOriginalContext;
838 }
839
840 private void setContext(Context context) {
841 mApplicationContext = context.getApplicationContext();
842 if (mApplicationContext != null) {
843 mOriginalContext = null;
844 } else {
845 mOriginalContext = context;
846 }
jiabin0f3339c2021-07-09 11:50:07 -0700847 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700848 }
849
Mathew Inwood31a792a2018-08-17 08:54:26 +0100850 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700851 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 {
853 if (sService != null) {
854 return sService;
855 }
856 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
857 sService = IAudioService.Stub.asInterface(b);
858 return sService;
859 }
860
861 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700862 * Sends a simulated key event for a media button.
863 * To simulate a key press, you must first send a KeyEvent built with a
864 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
865 * action.
866 * <p>The key event will be sent to the current media key event consumer which registered with
867 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
868 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
869 * {@link KeyEvent#KEYCODE_MUTE},
870 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
871 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
872 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
873 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
874 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
875 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
876 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
877 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
878 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
879 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
880 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
881 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
882 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700883 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700884 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700885 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700886 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700887 }
888
889 /**
890 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700891 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800892 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700893 /*
894 * If the user hits another key within the play sound delay, then
895 * cancel the sound
896 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800897 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700898 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
899 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500900 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700901 /*
902 * The user has hit another key during the delay (e.g., 300ms)
903 * since the last volume key up, so cancel any sounds.
904 */
John Spurlockee5ad722015-03-03 16:17:21 -0500905 adjustSuggestedStreamVolume(ADJUST_SAME,
906 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700907 }
908 }
909
910 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700911 * Indicates if the device implements a fixed volume policy.
912 * <p>Some devices may not have volume control and may operate at a fixed volume,
913 * and may not enable muting or changing the volume of audio streams.
914 * This method will return true on such devices.
915 * <p>The following APIs have no effect when volume is fixed:
916 * <ul>
917 * <li> {@link #adjustVolume(int, int)}
918 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
919 * <li> {@link #adjustStreamVolume(int, int, int)}
920 * <li> {@link #setStreamVolume(int, int, int)}
921 * <li> {@link #setRingerMode(int)}
922 * <li> {@link #setStreamSolo(int, boolean)}
923 * <li> {@link #setStreamMute(int, boolean)}
924 * </ul>
925 */
926 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700927 boolean res = false;
928 try {
929 res = getService().isVolumeFixed();
930 } catch (RemoteException e) {
931 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700932 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700933 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700934 }
935
936 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700938 * <p>
939 * This method should only be used by applications that replace the platform-wide
940 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700941 * <p>This method has no effect if the device implements a fixed volume policy
942 * as indicated by {@link #isVolumeFixed()}.
943 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
944 * unless the app has been granted Do Not Disturb Access.
945 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 *
947 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800948 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
949 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 * @param direction The direction to adjust the volume. One of
951 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
952 * {@link #ADJUST_SAME}.
953 * @param flags One or more flags.
954 * @see #adjustVolume(int, int)
955 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700956 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
957 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 */
959 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700960 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 try {
John Wu4f7e5102021-06-22 17:29:11 +0000962 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
963 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700965 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 }
967 }
968
969 /**
970 * Adjusts the volume of the most relevant stream. For example, if a call is
971 * active, it will have the highest priority regardless of if the in-call
972 * screen is showing. Another example, if music is playing in the background
973 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700974 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800975 * This method should only be used by applications that replace the
976 * platform-wide management of audio settings or the main telephony
977 * application.
978 * <p>
979 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700980 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800981 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800983 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
984 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
985 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 * @param flags One or more flags.
987 * @see #adjustSuggestedStreamVolume(int, int, int)
988 * @see #adjustStreamVolume(int, int, int)
989 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700990 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 */
992 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700993 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500994 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
997 /**
998 * Adjusts the volume of the most relevant stream, or the given fallback
999 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001000 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001001 * This method should only be used by applications that replace the
1002 * platform-wide management of audio settings or the main telephony
1003 * application.
1004 * <p>
1005 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001006 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001007 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -08001009 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1010 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1011 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -08001013 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1014 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 * @param flags One or more flags.
1016 * @see #adjustVolume(int, int)
1017 * @see #adjustStreamVolume(int, int, int)
1018 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -07001019 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 */
1021 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -07001022 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -05001023 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001024 }
1025
John Spurlockee5ad722015-03-03 16:17:21 -05001026 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001027 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -07001028 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001029 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001030 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001031 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001032 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001033 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001034 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001035 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
1037 }
1038
1039 /**
1040 * Returns the current ringtone mode.
1041 *
1042 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1043 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1044 * @see #setRingerMode(int)
1045 */
1046 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001047 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001049 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001051 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053 }
1054
1055 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001056 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1057 *
1058 * @return true if the incoming phone call ringtone is configured to gradually increase its
1059 * volume, false otherwise.
1060 */
1061 public boolean isRampingRingerEnabled() {
1062 return Settings.System.getInt(getContext().getContentResolver(),
1063 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1064 }
1065
1066 /**
1067 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1068 *
1069 * @see #isRampingRingerEnabled()
1070 * @hide
1071 */
1072 @TestApi
1073 public void setRampingRingerEnabled(boolean enabled) {
1074 Settings.System.putInt(getContext().getContentResolver(),
1075 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1076 }
1077
1078 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001079 * Checks valid ringer mode values.
1080 *
1081 * @return true if the ringer mode indicated is valid, false otherwise.
1082 *
1083 * @see #setRingerMode(int)
1084 * @hide
1085 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001086 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001087 public static boolean isValidRingerMode(int ringerMode) {
1088 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1089 return false;
1090 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001091 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001092 try {
1093 return service.isValidRingerMode(ringerMode);
1094 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001095 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001096 }
Eric Laurent72668b22011-07-19 16:04:27 -07001097 }
1098
1099 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 * Returns the maximum volume index for a particular stream.
1101 *
1102 * @param streamType The stream type whose maximum volume index is returned.
1103 * @return The maximum valid volume index for the stream.
1104 * @see #getStreamVolume(int)
1105 */
1106 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001107 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001109 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001111 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
1113 }
1114
1115 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001116 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001117 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1118 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1119 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1120 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1121 * @return The minimum valid volume index for the stream.
1122 * @see #getStreamVolume(int)
1123 */
1124 public int getStreamMinVolume(int streamType) {
1125 if (!isPublicStreamType(streamType)) {
1126 throw new IllegalArgumentException("Invalid stream type " + streamType);
1127 }
1128 return getStreamMinVolumeInt(streamType);
1129 }
1130
1131 /**
1132 * @hide
1133 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001134 * @param streamType The stream type whose minimum volume index is returned.
1135 * @return The minimum valid volume index for the stream.
1136 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001137 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001138 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001139 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001140 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001141 try {
1142 return service.getStreamMinVolume(streamType);
1143 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001144 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001145 }
1146 }
1147
1148 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 * Returns the current volume index for a particular stream.
1150 *
1151 * @param streamType The stream type whose volume index is returned.
1152 * @return The current volume index for the stream.
1153 * @see #getStreamMaxVolume(int)
1154 * @see #setStreamVolume(int, int, int)
1155 */
1156 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001157 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001159 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001161 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163 }
1164
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001165 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1166 private static final float VOLUME_MIN_DB = -758.0f;
1167
1168 /** @hide */
1169 @IntDef(flag = false, prefix = "STREAM", value = {
1170 STREAM_VOICE_CALL,
1171 STREAM_SYSTEM,
1172 STREAM_RING,
1173 STREAM_MUSIC,
1174 STREAM_ALARM,
1175 STREAM_NOTIFICATION,
1176 STREAM_DTMF,
1177 STREAM_ACCESSIBILITY }
1178 )
1179 @Retention(RetentionPolicy.SOURCE)
1180 public @interface PublicStreamTypes {}
1181
1182 /**
1183 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1184 * the given type of audio output device.
1185 * @param streamType stream type for which the volume is queried.
1186 * @param index the volume index for which the volume is queried. The index value must be
1187 * between the minimum and maximum index values for the given stream type (see
1188 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1189 * @param deviceType the type of audio output device for which volume is queried.
1190 * @return a volume expressed in dB.
1191 * A negative value indicates the audio signal is attenuated. A typical maximum value
1192 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1193 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1194 */
1195 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1196 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1197 if (!isPublicStreamType(streamType)) {
1198 throw new IllegalArgumentException("Invalid stream type " + streamType);
1199 }
1200 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1201 throw new IllegalArgumentException("Invalid stream volume index " + index);
1202 }
1203 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1204 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1205 }
1206 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1207 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1208 if (gain <= VOLUME_MIN_DB) {
1209 return Float.NEGATIVE_INFINITY;
1210 } else {
1211 return gain;
1212 }
1213 }
1214
1215 private static boolean isPublicStreamType(int streamType) {
1216 switch (streamType) {
1217 case STREAM_VOICE_CALL:
1218 case STREAM_SYSTEM:
1219 case STREAM_RING:
1220 case STREAM_MUSIC:
1221 case STREAM_ALARM:
1222 case STREAM_NOTIFICATION:
1223 case STREAM_DTMF:
1224 case STREAM_ACCESSIBILITY:
1225 return true;
1226 default:
1227 return false;
1228 }
1229 }
1230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001232 * Get last audible volume before stream was muted.
1233 *
1234 * @hide
1235 */
wescandee178f8f2021-10-19 20:15:09 +02001236 @SystemApi
1237 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
Eric Laurent25101b02011-02-02 09:33:30 -08001238 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001239 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001240 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001241 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001242 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001243 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001244 }
1245 }
1246
1247 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001248 * Get the stream type whose volume is driving the UI sounds volume.
1249 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001250 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001251 * @hide
1252 */
John Spurlockee5ad722015-03-03 16:17:21 -05001253 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001254 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001255 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001256 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001257 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001258 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001259 }
1260 }
1261
1262 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 * Sets the ringer mode.
1264 * <p>
1265 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1266 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1267 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001268 * <p>This method has no effect if the device implements a fixed volume policy
1269 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001270 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1271 * unless the app has been granted Do Not Disturb Access.
1272 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1274 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1275 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001276 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 */
1278 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001279 if (!isValidRingerMode(ringerMode)) {
1280 return;
1281 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001282 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001284 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001286 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 }
1288 }
1289
1290 /**
1291 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001292 * <p>This method has no effect if the device implements a fixed volume policy
1293 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001294 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1295 * the app has been granted Do Not Disturb Access.
1296 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 * @param streamType The stream whose volume index should be set.
1298 * @param index The volume index to set. See
1299 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1300 * @param flags One or more flags.
1301 * @see #getStreamMaxVolume(int)
1302 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001303 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001304 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1305 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 */
1307 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001308 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 try {
John Wu4f7e5102021-06-22 17:29:11 +00001310 service.setStreamVolumeWithAttribution(streamType, index, flags,
1311 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001313 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 }
1315 }
1316
1317 /**
François Gaffie9c362102018-09-21 17:43:52 +02001318 * Sets the volume index for a particular {@link AudioAttributes}.
1319 * @param attr The {@link AudioAttributes} whose volume index should be set.
1320 * @param index The volume index to set. See
1321 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1322 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1323 * @param flags One or more flags.
1324 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1325 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1326 * @see #isVolumeFixed()
1327 * @hide
1328 */
1329 @SystemApi
1330 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1331 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1332 Preconditions.checkNotNull(attr, "attr must not be null");
1333 final IAudioService service = getService();
1334 try {
1335 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001336 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001337 } catch (RemoteException e) {
1338 throw e.rethrowFromSystemServer();
1339 }
1340 }
1341
1342 /**
1343 * Returns the current volume index for a particular {@link AudioAttributes}.
1344 *
1345 * @param attr The {@link AudioAttributes} whose volume index is returned.
1346 * @return The current volume index for the stream.
1347 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1348 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1349 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1350 * @hide
1351 */
1352 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001353 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001354 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1355 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1356 Preconditions.checkNotNull(attr, "attr must not be null");
1357 final IAudioService service = getService();
1358 try {
1359 return service.getVolumeIndexForAttributes(attr);
1360 } catch (RemoteException e) {
1361 throw e.rethrowFromSystemServer();
1362 }
1363 }
1364
1365 /**
1366 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1367 *
1368 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1369 * @return The maximum valid volume index for the {@link AudioAttributes}.
1370 * @see #getVolumeIndexForAttributes(AudioAttributes)
1371 * @hide
1372 */
1373 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001374 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001375 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1376 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1377 Preconditions.checkNotNull(attr, "attr must not be null");
1378 final IAudioService service = getService();
1379 try {
1380 return service.getMaxVolumeIndexForAttributes(attr);
1381 } catch (RemoteException e) {
1382 throw e.rethrowFromSystemServer();
1383 }
1384 }
1385
1386 /**
1387 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1388 *
1389 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1390 * @return The minimum valid volume index for the {@link AudioAttributes}.
1391 * @see #getVolumeIndexForAttributes(AudioAttributes)
1392 * @hide
1393 */
1394 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001395 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001396 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1397 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1398 Preconditions.checkNotNull(attr, "attr must not be null");
1399 final IAudioService service = getService();
1400 try {
1401 return service.getMinVolumeIndexForAttributes(attr);
1402 } catch (RemoteException e) {
1403 throw e.rethrowFromSystemServer();
1404 }
1405 }
1406
1407 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001408 * Set the system usages to be supported on this device.
1409 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1410 * @hide
1411 */
1412 @SystemApi
1413 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1414 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1415 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1416 final IAudioService service = getService();
1417 try {
1418 service.setSupportedSystemUsages(systemUsages);
1419 } catch (RemoteException e) {
1420 throw e.rethrowFromSystemServer();
1421 }
1422 }
1423
1424 /**
1425 * Get the system usages supported on this device.
1426 * @return array of supported system usages {@link AttributeSystemUsage}
1427 * @hide
1428 */
1429 @SystemApi
1430 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1431 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1432 final IAudioService service = getService();
1433 try {
1434 return service.getSupportedSystemUsages();
1435 } catch (RemoteException e) {
1436 throw e.rethrowFromSystemServer();
1437 }
1438 }
1439
1440 /**
RoboErik4197cb62015-01-21 15:45:32 -08001441 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001443 * Do not use. This method has been deprecated and is now a no-op.
1444 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 *
1446 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001447 * @param state The required solo state: true for solo ON, false for solo
1448 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001449 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001450 * @deprecated Do not use. If you need exclusive audio playback use
1451 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 */
RoboErik4197cb62015-01-21 15:45:32 -08001453 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001455 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457
1458 /**
1459 * Mute or unmute an audio stream.
1460 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001461 * This method should only be used by applications that replace the
1462 * platform-wide management of audio settings or the main telephony
1463 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001465 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001466 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001467 * <p>
1468 * This method was deprecated in API level 22. Prior to API level 22 this
1469 * method had significantly different behavior and should be used carefully.
1470 * The following applies only to pre-22 platforms:
1471 * <ul>
1472 * <li>The mute command is protected against client process death: if a
1473 * process with an active mute request on a stream dies, this stream will be
1474 * unmuted automatically.</li>
1475 * <li>The mute requests for a given stream are cumulative: the AudioManager
1476 * can receive several mute requests from one or more clients and the stream
1477 * will be unmuted only when the same number of unmute requests are
1478 * received.</li>
1479 * <li>For a better user experience, applications MUST unmute a muted stream
1480 * in onPause() and mute is again in onResume() if appropriate.</li>
1481 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 *
1483 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001484 * @param state The required mute state: true for mute ON, false for mute
1485 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001486 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001487 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1488 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 */
RoboErik4197cb62015-01-21 15:45:32 -08001490 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001492 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1493 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1494 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1495 adjustSuggestedStreamVolume(direction, streamType, 0);
1496 } else {
1497 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 }
1499 }
1500
1501 /**
RoboErik4197cb62015-01-21 15:45:32 -08001502 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001503 *
RoboErik4197cb62015-01-21 15:45:32 -08001504 * @param streamType The stream to get mute state for.
1505 * @return The mute state for the given stream.
1506 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001507 */
1508 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001509 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001510 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001511 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001512 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001513 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001514 }
1515 }
1516
1517 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001518 * get master mute state.
1519 *
1520 * @hide
1521 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001522 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001523 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001524 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001525 try {
1526 return service.isMasterMute();
1527 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001528 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001529 }
1530 }
1531
1532 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001533 * forces the stream controlled by hard volume keys
1534 * specifying streamType == -1 releases control to the
1535 * logic.
1536 *
1537 * @hide
1538 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001539 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001540 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001541 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001542 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001543 try {
1544 service.forceVolumeControlStream(streamType, mICallBack);
1545 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001546 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001547 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001548 }
1549
1550 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 * Returns whether a particular type should vibrate according to user
1552 * settings and the current ringer mode.
1553 * <p>
1554 * This shouldn't be needed by most clients that use notifications to
1555 * vibrate. The notification manager will not vibrate if the policy doesn't
1556 * allow it, so the client should always set a vibrate pattern and let the
1557 * notification manager control whether or not to actually vibrate.
1558 *
1559 * @param vibrateType The type of vibrate. One of
1560 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1561 * {@link #VIBRATE_TYPE_RINGER}.
1562 * @return Whether the type should vibrate at the instant this method is
1563 * called.
1564 * @see #setVibrateSetting(int, int)
1565 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001566 * @deprecated Applications should maintain their own vibrate policy based on
1567 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 */
1569 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001570 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 try {
1572 return service.shouldVibrate(vibrateType);
1573 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001574 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 }
1576 }
1577
1578 /**
1579 * Returns whether the user's vibrate setting for a vibrate type.
1580 * <p>
1581 * This shouldn't be needed by most clients that want to vibrate, instead
1582 * see {@link #shouldVibrate(int)}.
1583 *
1584 * @param vibrateType The type of vibrate. One of
1585 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1586 * {@link #VIBRATE_TYPE_RINGER}.
1587 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1588 * {@link #VIBRATE_SETTING_OFF}, or
1589 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1590 * @see #setVibrateSetting(int, int)
1591 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001592 * @deprecated Applications should maintain their own vibrate policy based on
1593 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 */
1595 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001596 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 try {
1598 return service.getVibrateSetting(vibrateType);
1599 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001600 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 }
1602 }
1603
1604 /**
1605 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001606 * <p>
1607 * This method should only be used by applications that replace the platform-wide
1608 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 *
1610 * @param vibrateType The type of vibrate. One of
1611 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1612 * {@link #VIBRATE_TYPE_RINGER}.
1613 * @param vibrateSetting The vibrate setting, one of
1614 * {@link #VIBRATE_SETTING_ON},
1615 * {@link #VIBRATE_SETTING_OFF}, or
1616 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1617 * @see #getVibrateSetting(int)
1618 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001619 * @deprecated Applications should maintain their own vibrate policy based on
1620 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 */
1622 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001623 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 try {
1625 service.setVibrateSetting(vibrateType, vibrateSetting);
1626 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001627 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 }
1629 }
1630
1631 /**
1632 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001633 * <p>
1634 * This method should only be used by applications that replace the platform-wide
1635 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 *
1637 * @param on set <var>true</var> to turn on speakerphone;
1638 * <var>false</var> to turn it off
1639 */
1640 public void setSpeakerphoneOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001641 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001642 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001643 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001644 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001645 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 }
1648
1649 /**
1650 * Checks whether the speakerphone is on or off.
1651 *
1652 * @return true if speakerphone is on, false if it's off
1653 */
1654 public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001655 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001656 try {
1657 return service.isSpeakerphoneOn();
1658 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001659 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 }
1662
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001663 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001664 * 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 -07001665 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001666 *
1667 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1668 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001669 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001670 * <ul>
1671 * <li> for each track independently, see
1672 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1673 * <li> application-wide at runtime, with this method </li>
1674 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1675 * manifest. </li>
1676 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001677 * The most restrictive policy is always applied.
1678 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001679 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001680 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001681 *
1682 * @param capturePolicy one of
1683 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1684 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1685 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001686 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001687 */
1688 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001689 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001690 final IAudioService service = getService();
1691 try {
1692 int result = service.setAllowedCapturePolicy(capturePolicy);
1693 if (result != AudioSystem.AUDIO_STATUS_OK) {
1694 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1695 return;
1696 }
1697 } catch (RemoteException e) {
1698 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001699 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001700 }
1701
Kevin Rocard019f60d2019-04-09 16:25:26 -07001702 /**
1703 * Return the capture policy.
1704 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1705 * the default if it was not called.
1706 */
1707 @AudioAttributes.CapturePolicy
1708 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001709 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1710 try {
1711 result = getService().getAllowedCapturePolicy();
1712 } catch (RemoteException e) {
1713 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1714 }
1715 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001716 }
1717
Eric Laurent3def1ee2010-03-17 23:26:26 -07001718 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001719 // Audio Product Strategy routing
1720
1721 /**
1722 * @hide
1723 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1724 * this audio strategy. Note that the device may not be available at the time the preferred
1725 * device is set, but it will be used once made available.
1726 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1727 * this preference for this strategy.</p>
1728 * @param strategy the audio strategy whose routing will be affected
1729 * @param device the audio device to route to when available
1730 * @return true if the operation was successful, false otherwise
1731 */
1732 @SystemApi
1733 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1734 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001735 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001736 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001737 }
1738
1739 /**
1740 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001741 * Removes the preferred audio device(s) previously set with
1742 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1743 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001744 * @param strategy the audio strategy whose routing will be affected
1745 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1746 * device set for example)
1747 */
1748 @SystemApi
1749 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1750 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1751 Objects.requireNonNull(strategy);
1752 try {
1753 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001754 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001755 return status == AudioSystem.SUCCESS;
1756 } catch (RemoteException e) {
1757 throw e.rethrowFromSystemServer();
1758 }
1759 }
1760
1761 /**
1762 * @hide
1763 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001764 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1765 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1766 * @param strategy the strategy to query
1767 * @return the preferred device for that strategy, if multiple devices are set as preferred
1768 * devices, the first one in the list will be returned. Null will be returned if none was
1769 * ever set or if the strategy is invalid
1770 */
1771 @SystemApi
1772 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1773 @Nullable
1774 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1775 @NonNull AudioProductStrategy strategy) {
1776 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1777 return devices.isEmpty() ? null : devices.get(0);
1778 }
1779
1780 /**
1781 * @hide
1782 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1783 * this audio strategy. Note that the devices may not be available at the time the preferred
1784 * devices is set, but it will be used once made available.
1785 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1786 * this preference for this strategy.</p>
1787 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1788 * devices used simultaneously to output the same audio signal.
1789 * @param strategy the audio strategy whose routing will be affected
1790 * @param devices a non-empty list of the audio devices to route to when available
1791 * @return true if the operation was successful, false otherwise
1792 */
1793 @SystemApi
1794 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1795 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1796 @NonNull List<AudioDeviceAttributes> devices) {
1797 Objects.requireNonNull(strategy);
1798 Objects.requireNonNull(devices);
1799 if (devices.isEmpty()) {
1800 throw new IllegalArgumentException(
1801 "Tried to set preferred devices for strategy with a empty list");
1802 }
1803 for (AudioDeviceAttributes device : devices) {
1804 Objects.requireNonNull(device);
1805 }
1806 try {
1807 final int status =
1808 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1809 return status == AudioSystem.SUCCESS;
1810 } catch (RemoteException e) {
1811 throw e.rethrowFromSystemServer();
1812 }
1813 }
1814
1815 /**
1816 * @hide
1817 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001818 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001819 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001820 * @param strategy the strategy to query
1821 * @return the preferred device for that strategy, or null if none was ever set or if the
1822 * strategy is invalid
1823 */
1824 @SystemApi
1825 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001826 @NonNull
1827 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001828 @NonNull AudioProductStrategy strategy) {
1829 Objects.requireNonNull(strategy);
1830 try {
jiabinf40141d2020-08-07 17:27:48 -07001831 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001832 } catch (RemoteException e) {
1833 throw e.rethrowFromSystemServer();
1834 }
1835 }
1836
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001837 /**
1838 * @hide
1839 * Interface to be notified of changes in the preferred audio device set for a given audio
1840 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001841 * <p>Note that this listener will only be invoked whenever
1842 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001843 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001844 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1845 * preferred device. It will not be invoked directly after registration with
1846 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1847 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001848 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001849 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1850 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001851 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001852 */
1853 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001854 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001855 public interface OnPreferredDeviceForStrategyChangedListener {
1856 /**
1857 * Called on the listener to indicate that the preferred audio device for the given
1858 * strategy has changed.
1859 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1860 * @param device <code>null</code> if the preferred device was removed, or the newly set
1861 * preferred audio device
1862 */
1863 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001864 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001865 }
1866
1867 /**
1868 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001869 * Interface to be notified of changes in the preferred audio devices set for a given audio
1870 * strategy.
1871 * <p>Note that this listener will only be invoked whenever
1872 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1873 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1874 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1875 * preferred device(s). It will not be invoked directly after registration with
1876 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1877 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1878 * to indicate which strategies had preferred devices at the time of registration.</p>
1879 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1880 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1881 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1882 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
1883 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1884 */
1885 @SystemApi
1886 public interface OnPreferredDevicesForStrategyChangedListener {
1887 /**
1888 * Called on the listener to indicate that the preferred audio devices for the given
1889 * strategy has changed.
1890 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1891 * @param devices a list of newly set preferred audio devices
1892 */
1893 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1894 @NonNull List<AudioDeviceAttributes> devices);
1895 }
1896
1897 /**
1898 * @hide
1899 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1900 * @param executor
1901 * @param listener
1902 * @throws SecurityException if the caller doesn't hold the required permission
1903 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1904 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1905 */
1906 @SystemApi
1907 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1908 @Deprecated
1909 public void addOnPreferredDeviceForStrategyChangedListener(
1910 @NonNull @CallbackExecutor Executor executor,
1911 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
1912 throws SecurityException {
1913 // No-op, the method is deprecated.
1914 }
1915
1916 /**
1917 * @hide
1918 * Removes a previously added listener of changes to the strategy-preferred audio device.
1919 * @param listener
1920 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
1921 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1922 */
1923 @SystemApi
1924 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1925 @Deprecated
1926 public void removeOnPreferredDeviceForStrategyChangedListener(
1927 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
1928 // No-op, the method is deprecated.
1929 }
1930
1931 /**
1932 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001933 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1934 * @param executor
1935 * @param listener
1936 * @throws SecurityException if the caller doesn't hold the required permission
1937 */
1938 @SystemApi
1939 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001940 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001941 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07001942 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001943 throws SecurityException {
1944 Objects.requireNonNull(executor);
1945 Objects.requireNonNull(listener);
1946 synchronized (mPrefDevListenerLock) {
1947 if (hasPrefDevListener(listener)) {
1948 throw new IllegalArgumentException(
jiabinf40141d2020-08-07 17:27:48 -07001949 "attempt to call addOnPreferredDevicesForStrategyChangedListener() "
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001950 + "on a previously registered listener");
1951 }
1952 // lazy initialization of the list of strategy-preferred device listener
1953 if (mPrefDevListeners == null) {
1954 mPrefDevListeners = new ArrayList<>();
1955 }
1956 final int oldCbCount = mPrefDevListeners.size();
1957 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor));
1958 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) {
1959 // register binder for callbacks
1960 if (mPrefDevDispatcherStub == null) {
jiabinf40141d2020-08-07 17:27:48 -07001961 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001962 }
1963 try {
jiabinf40141d2020-08-07 17:27:48 -07001964 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001965 } catch (RemoteException e) {
1966 throw e.rethrowFromSystemServer();
1967 }
1968 }
1969 }
1970 }
1971
1972 /**
1973 * @hide
1974 * Removes a previously added listener of changes to the strategy-preferred audio device.
1975 * @param listener
1976 */
1977 @SystemApi
1978 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001979 public void removeOnPreferredDevicesForStrategyChangedListener(
1980 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001981 Objects.requireNonNull(listener);
1982 synchronized (mPrefDevListenerLock) {
1983 if (!removePrefDevListener(listener)) {
1984 throw new IllegalArgumentException(
1985 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() "
1986 + "on an unregistered listener");
1987 }
1988 if (mPrefDevListeners.size() == 0) {
1989 // unregister binder for callbacks
1990 try {
jiabinf40141d2020-08-07 17:27:48 -07001991 getService().unregisterStrategyPreferredDevicesDispatcher(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001992 mPrefDevDispatcherStub);
1993 } catch (RemoteException e) {
1994 throw e.rethrowFromSystemServer();
1995 } finally {
1996 mPrefDevDispatcherStub = null;
1997 mPrefDevListeners = null;
1998 }
1999 }
2000 }
2001 }
2002
2003
2004 private final Object mPrefDevListenerLock = new Object();
2005 /**
2006 * List of listeners for preferred device for strategy and their associated Executor.
2007 * List is lazy-initialized on first registration
2008 */
2009 @GuardedBy("mPrefDevListenerLock")
2010 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners;
2011
2012 private static class PrefDevListenerInfo {
jiabinf40141d2020-08-07 17:27:48 -07002013 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002014 final @NonNull Executor mExecutor;
jiabinf40141d2020-08-07 17:27:48 -07002015 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002016 mListener = listener;
2017 mExecutor = exe;
2018 }
2019 }
2020
2021 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002022 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002023
jiabinf40141d2020-08-07 17:27:48 -07002024 private final class StrategyPreferredDevicesDispatcherStub
2025 extends IStrategyPreferredDevicesDispatcher.Stub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002026
2027 @Override
jiabinf40141d2020-08-07 17:27:48 -07002028 public void dispatchPrefDevicesChanged(int strategyId,
2029 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002030 // make a shallow copy of listeners so callback is not executed under lock
2031 final ArrayList<PrefDevListenerInfo> prefDevListeners;
2032 synchronized (mPrefDevListenerLock) {
2033 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) {
2034 return;
2035 }
2036 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone();
2037 }
2038 final AudioProductStrategy strategy =
2039 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2040 final long ident = Binder.clearCallingIdentity();
2041 try {
2042 for (PrefDevListenerInfo info : prefDevListeners) {
2043 info.mExecutor.execute(() ->
jiabinf40141d2020-08-07 17:27:48 -07002044 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices));
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002045 }
2046 } finally {
2047 Binder.restoreCallingIdentity(ident);
2048 }
2049 }
2050 }
2051
2052 @GuardedBy("mPrefDevListenerLock")
2053 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo(
jiabinf40141d2020-08-07 17:27:48 -07002054 OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002055 if (mPrefDevListeners == null) {
2056 return null;
2057 }
2058 for (PrefDevListenerInfo info : mPrefDevListeners) {
2059 if (info.mListener == listener) {
2060 return info;
2061 }
2062 }
2063 return null;
2064 }
2065
2066 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002067 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002068 return getPrefDevListenerInfo(listener) != null;
2069 }
2070
2071 @GuardedBy("mPrefDevListenerLock")
2072 /**
2073 * @return true if the listener was removed from the list
2074 */
jiabinf40141d2020-08-07 17:27:48 -07002075 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002076 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener);
2077 if (infoToRemove != null) {
2078 mPrefDevListeners.remove(infoToRemove);
2079 return true;
2080 }
2081 return false;
2082 }
2083
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002084 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002085 // Audio Capture Preset routing
2086
2087 /**
2088 * @hide
2089 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2090 * this capture preset. Note that the device may not be available at the time the preferred
2091 * device is set, but it will be used once made available.
2092 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2093 * for this capture preset.</p>
2094 * @param capturePreset the audio capture preset whose routing will be affected
2095 * @param device the audio device to route to when available
2096 * @return true if the operation was successful, false otherwise
2097 */
2098 @SystemApi
2099 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002100 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002101 @NonNull AudioDeviceAttributes device) {
2102 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2103 }
2104
2105 /**
2106 * @hide
2107 * Remove all the preferred audio devices previously set
2108 * @param capturePreset the audio capture preset whose routing will be affected
2109 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2110 * device set for example)
2111 */
2112 @SystemApi
2113 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002114 public boolean clearPreferredDevicesForCapturePreset(
2115 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002116 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2117 return false;
2118 }
2119 try {
2120 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2121 return status == AudioSystem.SUCCESS;
2122 } catch (RemoteException e) {
2123 throw e.rethrowFromSystemServer();
2124 }
2125 }
2126
2127 /**
2128 * @hide
2129 * Return the preferred devices for an audio capture preset, previously set with
2130 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2131 * @param capturePreset the capture preset to query
2132 * @return a list that contains preferred devices for that capture preset.
2133 */
2134 @NonNull
2135 @SystemApi
2136 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002137 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2138 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002139 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2140 return new ArrayList<AudioDeviceAttributes>();
2141 }
2142 try {
2143 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2144 } catch (RemoteException e) {
2145 throw e.rethrowFromSystemServer();
2146 }
2147 }
2148
2149 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002150 @MediaRecorder.SystemSource int capturePreset,
2151 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002152 Objects.requireNonNull(devices);
2153 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2154 return false;
2155 }
2156 if (devices.size() != 1) {
2157 throw new IllegalArgumentException(
2158 "Only support setting one preferred devices for capture preset");
2159 }
2160 for (AudioDeviceAttributes device : devices) {
2161 Objects.requireNonNull(device);
2162 }
2163 try {
2164 final int status =
2165 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2166 return status == AudioSystem.SUCCESS;
2167 } catch (RemoteException e) {
2168 throw e.rethrowFromSystemServer();
2169 }
2170 }
2171
2172 /**
2173 * @hide
2174 * Interface to be notified of changes in the preferred audio devices set for a given capture
2175 * preset.
2176 * <p>Note that this listener will only be invoked whenever
2177 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2178 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2179 * preferred device. It will not be invoked directly after registration with
2180 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2181 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2182 * to indicate which strategies had preferred devices at the time of registration.</p>
2183 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2184 * @see #clearPreferredDevicesForCapturePreset(int)
2185 * @see #getPreferredDevicesForCapturePreset(int)
2186 */
2187 @SystemApi
2188 public interface OnPreferredDevicesForCapturePresetChangedListener {
2189 /**
2190 * Called on the listener to indicate that the preferred audio devices for the given
2191 * capture preset has changed.
2192 * @param capturePreset the capture preset whose preferred device changed
2193 * @param devices a list of newly set preferred audio devices
2194 */
2195 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002196 @MediaRecorder.SystemSource int capturePreset,
2197 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002198 }
2199
2200 /**
2201 * @hide
2202 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2203 * @param executor
2204 * @param listener
2205 * @throws SecurityException if the caller doesn't hold the required permission
2206 */
2207 @SystemApi
2208 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2209 public void addOnPreferredDevicesForCapturePresetChangedListener(
2210 @NonNull @CallbackExecutor Executor executor,
2211 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2212 throws SecurityException {
2213 Objects.requireNonNull(executor);
2214 Objects.requireNonNull(listener);
2215 int status = addOnDevRoleForCapturePresetChangedListener(
2216 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2217 if (status == AudioSystem.ERROR) {
2218 // This must not happen
2219 throw new RuntimeException("Unknown error happened");
2220 }
2221 if (status == AudioSystem.BAD_VALUE) {
2222 throw new IllegalArgumentException(
2223 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2224 + "on a previously registered listener");
2225 }
2226 }
2227
2228 /**
2229 * @hide
2230 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2231 * @param listener
2232 */
2233 @SystemApi
2234 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2235 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2236 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2237 Objects.requireNonNull(listener);
2238 int status = removeOnDevRoleForCapturePresetChangedListener(
2239 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2240 if (status == AudioSystem.ERROR) {
2241 // This must not happen
2242 throw new RuntimeException("Unknown error happened");
2243 }
2244 if (status == AudioSystem.BAD_VALUE) {
2245 throw new IllegalArgumentException(
2246 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2247 + "on an unregistered listener");
2248 }
2249 }
2250
2251 private <T> int addOnDevRoleForCapturePresetChangedListener(
2252 @NonNull @CallbackExecutor Executor executor,
2253 @NonNull T listener, int deviceRole) {
2254 Objects.requireNonNull(executor);
2255 Objects.requireNonNull(listener);
2256 DevRoleListeners<T> devRoleListeners =
2257 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2258 if (devRoleListeners == null) {
2259 return AudioSystem.ERROR;
2260 }
2261 synchronized (devRoleListeners.mDevRoleListenersLock) {
2262 if (devRoleListeners.hasDevRoleListener(listener)) {
2263 return AudioSystem.BAD_VALUE;
2264 }
2265 // lazy initialization of the list of device role listener
2266 if (devRoleListeners.mListenerInfos == null) {
2267 devRoleListeners.mListenerInfos = new ArrayList<>();
2268 }
2269 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2270 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2271 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2272 // register binder for callbacks
2273 synchronized (mDevRoleForCapturePresetListenersLock) {
2274 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2275 mDeviceRoleListenersStatus |= (1 << deviceRole);
2276 if (deviceRoleListenerStatus != 0) {
2277 // There are already device role changed listeners active.
2278 return AudioSystem.SUCCESS;
2279 }
2280 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2281 mDevicesRoleForCapturePresetDispatcherStub =
2282 new CapturePresetDevicesRoleDispatcherStub();
2283 }
2284 try {
2285 getService().registerCapturePresetDevicesRoleDispatcher(
2286 mDevicesRoleForCapturePresetDispatcherStub);
2287 } catch (RemoteException e) {
2288 throw e.rethrowFromSystemServer();
2289 }
2290 }
2291 }
2292 }
2293 return AudioSystem.SUCCESS;
2294 }
2295
2296 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2297 @NonNull T listener, int deviceRole) {
2298 Objects.requireNonNull(listener);
2299 DevRoleListeners<T> devRoleListeners =
2300 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2301 if (devRoleListeners == null) {
2302 return AudioSystem.ERROR;
2303 }
2304 synchronized (devRoleListeners.mDevRoleListenersLock) {
2305 if (!devRoleListeners.removeDevRoleListener(listener)) {
2306 return AudioSystem.BAD_VALUE;
2307 }
2308 if (devRoleListeners.mListenerInfos.size() == 0) {
2309 // unregister binder for callbacks
2310 synchronized (mDevRoleForCapturePresetListenersLock) {
2311 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2312 if (mDeviceRoleListenersStatus != 0) {
2313 // There are some other device role changed listeners active.
2314 return AudioSystem.SUCCESS;
2315 }
2316 try {
2317 getService().unregisterCapturePresetDevicesRoleDispatcher(
2318 mDevicesRoleForCapturePresetDispatcherStub);
2319 } catch (RemoteException e) {
2320 throw e.rethrowFromSystemServer();
2321 }
2322 }
2323 }
2324 }
2325 return AudioSystem.SUCCESS;
2326 }
2327
Cole Faust7da659b2022-10-15 21:33:29 -07002328 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of(
2329 AudioSystem.DEVICE_ROLE_PREFERRED,
2330 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
Jiabin Huangb55305f2020-09-03 17:54:16 +00002331
2332 private class DevRoleListenerInfo<T> {
2333 final @NonNull Executor mExecutor;
2334 final @NonNull T mListener;
2335 DevRoleListenerInfo(Executor executor, T listener) {
2336 mExecutor = executor;
2337 mListener = listener;
2338 }
2339 }
2340
2341 private class DevRoleListeners<T> {
2342 private final Object mDevRoleListenersLock = new Object();
2343 @GuardedBy("mDevRoleListenersLock")
2344 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2345
2346 @GuardedBy("mDevRoleListenersLock")
2347 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2348 if (mListenerInfos == null) {
2349 return null;
2350 }
2351 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2352 if (listenerInfo.mListener == listener) {
2353 return listenerInfo;
2354 }
2355 }
2356 return null;
2357 }
2358
2359 @GuardedBy("mDevRoleListenersLock")
2360 private boolean hasDevRoleListener(T listener) {
2361 return getDevRoleListenerInfo(listener) != null;
2362 }
2363
2364 @GuardedBy("mDevRoleListenersLock")
2365 private boolean removeDevRoleListener(T listener) {
2366 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2367 if (infoToRemove != null) {
2368 mListenerInfos.remove(infoToRemove);
2369 return true;
2370 }
2371 return false;
2372 }
2373 }
2374
2375 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2376 /**
2377 * Record if there is a listener added for device role change. If there is a listener added for
2378 * a specified device role change, the bit at position `1 << device_role` is set.
2379 */
2380 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2381 private int mDeviceRoleListenersStatus = 0;
2382 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2383 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2384
2385 private final class CapturePresetDevicesRoleDispatcherStub
2386 extends ICapturePresetDevicesRoleDispatcher.Stub {
2387
2388 @Override
2389 public void dispatchDevicesRoleChanged(
2390 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2391 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2392 if (listenersObj == null) {
2393 return;
2394 }
2395 switch (role) {
2396 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2397 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2398 listeners =
2399 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2400 listenersObj;
2401 final ArrayList<DevRoleListenerInfo<
2402 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2403 synchronized (listeners.mDevRoleListenersLock) {
2404 if (listeners.mListenerInfos.isEmpty()) {
2405 return;
2406 }
2407 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2408 OnPreferredDevicesForCapturePresetChangedListener>>)
2409 listeners.mListenerInfos.clone();
2410 }
2411 final long ident = Binder.clearCallingIdentity();
2412 try {
2413 for (DevRoleListenerInfo<
2414 OnPreferredDevicesForCapturePresetChangedListener> info :
2415 prefDevListeners) {
2416 info.mExecutor.execute(() ->
2417 info.mListener.onPreferredDevicesForCapturePresetChanged(
2418 capturePreset, devices));
2419 }
2420 } finally {
2421 Binder.restoreCallingIdentity(ident);
2422 }
2423 } break;
2424 default:
2425 break;
2426 }
2427 }
2428 }
2429
2430 //====================================================================
jiabine22f6aa2021-12-10 01:09:02 +00002431 // Direct playback query
2432
2433 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2434 direct playback not supported. */
2435 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2436 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2437 direct offload playback supported. Compressed offload is a variant of direct playback.
2438 It is the feature that allows audio processing tasks to be done on the Android device but
2439 not on the application processor, instead, it is handled by dedicated hardware such as audio
2440 DSPs. That will allow the application processor to be idle as much as possible, which is
2441 good for power saving. Compressed offload playback supports
2442 {@link AudioTrack.StreamEventCallback} for event notifications. */
2443 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2444 AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2445 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2446 direct offload playback supported with gapless transitions. Compressed offload is a variant
2447 of direct playback. It is the feature that allows audio processing tasks to be done on the
2448 Android device but not on the application processor, instead, it is handled by dedicated
2449 hardware such as audio DSPs. That will allow the application processor to be idle as much as
2450 possible, which is good for power saving. Compressed offload playback supports
2451 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2452 indicates the ability to play consecutive audio tracks without an audio silence in
2453 between. */
2454 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2455 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2456 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2457 direct playback supported. This value covers direct playback that is bitstream pass-through
2458 such as compressed pass-through. */
2459 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2460 AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2461
2462 /** @hide */
2463 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2464 DIRECT_PLAYBACK_NOT_SUPPORTED,
2465 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2466 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2467 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2468 )
2469 @Retention(RetentionPolicy.SOURCE)
2470 public @interface AudioDirectPlaybackMode {}
2471
2472 /**
2473 * Returns a bitfield representing the different forms of direct playback currently available
2474 * for a given audio format.
2475 * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2476 * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2477 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2478 * passthrough.
2479 * <p>Checking for direct support can help the app select the representation of audio content
2480 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2481 * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2482 * streams, if needed.
2483 * @param format the audio format (codec, sample rate, channels) being checked.
2484 * @param attributes the {@link AudioAttributes} to be used for playback
2485 * @return the direct playback mode available with given format and attributes. The returned
2486 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2487 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2488 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2489 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2490 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2491 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2492 */
2493 @AudioDirectPlaybackMode
2494 public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2495 @NonNull AudioAttributes attributes) {
2496 Objects.requireNonNull(format);
2497 Objects.requireNonNull(attributes);
2498 return AudioSystem.getDirectPlaybackSupport(format, attributes);
2499 }
2500
2501 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002502 // Offload query
2503 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002504 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002505 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2506 * is not competing with other software resources. In general, it is supported by dedicated
2507 * hardware, such as audio DSPs.
2508 * <p>Note that this query only provides information about the support of an audio format,
2509 * it does not indicate whether the resources necessary for the offloaded playback are
2510 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002511 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002512 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002513 * @return true if the given audio format can be offloaded.
2514 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002515 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2516 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002517 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002518 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002519 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002520 if (attributes == null) {
2521 throw new NullPointerException("Illegal null AudioAttributes");
2522 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002523 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2524 }
2525
2526 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2527 offload playback not supported */
2528 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2529 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2530 offload playback supported */
2531 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2532 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2533 offload playback supported with gapless transitions */
2534 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2535 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2536
2537 /** @hide */
2538 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2539 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2540 PLAYBACK_OFFLOAD_SUPPORTED,
2541 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2542 )
2543 @Retention(RetentionPolicy.SOURCE)
2544 public @interface AudioOffloadMode {}
2545
2546 /**
2547 * Returns whether offloaded playback of an audio format is supported on the device or not and
2548 * when supported whether gapless transitions are possible or not.
2549 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2550 * is not competing with other software resources. In general, it is supported by dedicated
2551 * hardware, such as audio DSPs.
2552 * <p>Note that this query only provides information about the support of an audio format,
2553 * it does not indicate whether the resources necessary for the offloaded playback are
2554 * available at that instant.
2555 * @param format the audio format (codec, sample rate, channels) being checked.
2556 * @param attributes the {@link AudioAttributes} to be used for playback
2557 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2558 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2559 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2560 * also supported.
jiabine22f6aa2021-12-10 01:09:02 +00002561 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
Eric Laurentba3b3a62020-11-26 20:10:51 +01002562 */
jiabine22f6aa2021-12-10 01:09:02 +00002563 @Deprecated
Eric Laurentba3b3a62020-11-26 20:10:51 +01002564 @AudioOffloadMode
2565 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2566 @NonNull AudioAttributes attributes) {
2567 if (format == null) {
2568 throw new NullPointerException("Illegal null AudioFormat");
2569 }
2570 if (attributes == null) {
2571 throw new NullPointerException("Illegal null AudioAttributes");
2572 }
2573 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002574 }
2575
2576 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002577 // Immersive audio
2578
2579 /**
2580 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002581 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002582 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2583 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002584 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002585 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002586 return new Spatializer(this);
2587 }
2588
2589 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002590 // Bluetooth SCO control
2591 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002592 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002593 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002594 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2595 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2596 *
2597 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002598 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002599 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002600 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002601 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2602 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2603 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002604
2605 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002606 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002607 * connection state has been updated.
2608 * <p>This intent has two extras:
2609 * <ul>
2610 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2611 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2612 * </ul>
2613 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2614 * <ul>
2615 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2616 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2617 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2618 * </ul>
2619 * @see #startBluetoothSco()
2620 */
2621 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2622 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2623 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2624
Eric Laurent3def1ee2010-03-17 23:26:26 -07002625 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002626 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2627 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002628 */
2629 public static final String EXTRA_SCO_AUDIO_STATE =
2630 "android.media.extra.SCO_AUDIO_STATE";
2631
2632 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002633 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2634 * bluetooth SCO connection state.
2635 */
2636 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2637 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2638
2639 /**
2640 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2641 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002642 */
2643 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2644 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002645 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2646 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002647 */
2648 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2649 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002650 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2651 * indicating that the SCO audio channel is being established
2652 */
2653 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2654 /**
2655 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002656 * there was an error trying to obtain the state
2657 */
2658 public static final int SCO_AUDIO_STATE_ERROR = -1;
2659
2660
2661 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002662 * Indicates if current platform supports use of SCO for off call use cases.
2663 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002664 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002665 * feature.
2666 * @return true if bluetooth SCO can be used for audio when not in call
2667 * false otherwise
2668 * @see #startBluetoothSco()
2669 */
2670 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002671 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002672 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2673 }
2674
2675 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002676 * Start bluetooth SCO audio connection.
2677 * <p>Requires Permission:
2678 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2679 * <p>This method can be used by applications wanting to send and received audio
2680 * to/from a bluetooth SCO headset while the phone is not in call.
2681 * <p>As the SCO connection establishment can take several seconds,
2682 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002683 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002684 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002685 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2686 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2687 * registration. If the state is already CONNECTED, no state change will be received via the
2688 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2689 * so that the connection stays active in case the current initiator stops the connection.
2690 * <p>Unless the connection is already active as described above, the state will always
2691 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2692 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2693 * <p>When finished with the SCO connection or if the establishment fails, the application must
2694 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002695 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2696 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002697 * <ul>
2698 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2699 * <li> the format must be mono </li>
2700 * <li> the sampling must be 16kHz or 8kHz </li>
2701 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002702 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002703 * <ul>
2704 * <li> the format must be mono </li>
2705 * <li> the sampling must be 8kHz </li>
2706 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002707 * <p>Note that the phone application always has the priority on the usage of the SCO
2708 * connection for telephony. If this method is called while the phone is in call
2709 * it will be ignored. Similarly, if a call is received or sent while an application
2710 * is using the SCO connection, the connection will be lost for the application and NOT
2711 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002712 * <p>NOTE: up to and including API version
2713 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2714 * voice call to the bluetooth headset.
2715 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2716 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002717 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002718 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurent3def1ee2010-03-17 23:26:26 -07002719 */
2720 public void startBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002721 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002722 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002723 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002724 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002725 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002726 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002727 }
2728 }
2729
2730 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002731 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002732 * Start bluetooth SCO audio connection in virtual call mode.
2733 * <p>Requires Permission:
2734 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2735 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2736 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2737 * virtual call mode.
2738 * Applications using voice input for search or commands should first try raw audio connection
2739 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2740 * failure.
2741 * @see #startBluetoothSco()
2742 * @see #stopBluetoothSco()
2743 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2744 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002745 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002746 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002747 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002748 try {
2749 service.startBluetoothScoVirtualCall(mICallBack);
2750 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002751 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002752 }
2753 }
2754
2755 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002756 * Stop bluetooth SCO audio connection.
2757 * <p>Requires Permission:
2758 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2759 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002760 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2761 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002762 * @see #startBluetoothSco()
2763 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002764 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002765 public void stopBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002766 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002767 try {
2768 service.stopBluetoothSco(mICallBack);
2769 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002770 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002771 }
2772 }
2773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002774 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002775 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002776 * <p>
2777 * This method should only be used by applications that replace the platform-wide
2778 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 *
Eric Laurenta553c252009-07-17 12:17:14 -07002780 * @param on set <var>true</var> to use bluetooth SCO for communications;
2781 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 */
2783 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002784 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002785 try {
2786 service.setBluetoothScoOn(on);
2787 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002788 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 }
2791
2792 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002793 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002794 *
Eric Laurenta553c252009-07-17 12:17:14 -07002795 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 * false if otherwise
2797 */
2798 public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002799 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002800 try {
2801 return service.isBluetoothScoOn();
2802 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002803 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002805 }
2806
2807 /**
Eric Laurent242b3382012-06-15 11:48:50 -07002808 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2809 * headset; <var>false</var> disable A2DP audio
Eric Laurenta553c252009-07-17 12:17:14 -07002810 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002811 */
Eric Laurenta553c252009-07-17 12:17:14 -07002812 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002813 }
2814
2815 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002816 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002817 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002818 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002819 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002820 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 */
2822 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002823 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002824 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2825 return true;
2826 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2827 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2828 return true;
2829 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2830 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002831 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002832 }
Eric Laurent9656df22016-04-20 16:42:28 -07002833 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002834 }
2835
2836 /**
2837 * Sets audio routing to the wired headset on or off.
2838 *
2839 * @param on set <var>true</var> to route audio to/from wired
2840 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002841 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002842 */
Eric Laurenta553c252009-07-17 12:17:14 -07002843 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002844 }
2845
2846 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002847 * Checks whether a wired headset is connected or not.
2848 * <p>This is not a valid indication that audio playback is
2849 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002851 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002853 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 */
2855 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002856 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002857 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002858 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002859 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2860 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2861 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002862 return false;
2863 } else {
2864 return true;
2865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002866 }
2867
2868 /**
2869 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002870 * <p>
2871 * This method should only be used by applications that replace the platform-wide
2872 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002873 *
2874 * @param on set <var>true</var> to mute the microphone;
2875 * <var>false</var> to turn mute off
2876 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002877 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002878 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002879 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002880 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002881 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002882 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002883 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 }
2886
2887 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002888 * @hide
2889 * Sets the microphone from switch mute on or off.
2890 * <p>
2891 * This method should only be used by InputManager to notify
2892 * Audio Subsystem about Microphone Mute switch state.
2893 *
2894 * @param on set <var>true</var> to mute the microphone;
2895 * <var>false</var> to turn mute off
2896 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002897 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002898 public void setMicrophoneMuteFromSwitch(boolean on) {
2899 final IAudioService service = getService();
2900 try {
2901 service.setMicrophoneMuteFromSwitch(on);
2902 } catch (RemoteException e) {
2903 throw e.rethrowFromSystemServer();
2904 }
2905 }
2906
2907 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 * Checks whether the microphone mute is on or off.
2909 *
2910 * @return true if microphone is muted, false if it's not
2911 */
2912 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002913 final IAudioService service = getService();
2914 try {
2915 return service.isMicrophoneMuted();
2916 } catch (RemoteException e) {
2917 throw e.rethrowFromSystemServer();
2918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919 }
2920
2921 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002922 * Broadcast Action: microphone muting state changed.
2923 *
2924 * You <em>cannot</em> receive this through components declared
2925 * in manifests, only by explicitly registering for it with
2926 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2927 * Context.registerReceiver()}.
2928 *
2929 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2930 * microphone is muted.
2931 */
2932 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2933 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2934 "android.media.action.MICROPHONE_MUTE_CHANGED";
2935
2936 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07002937 * Broadcast Action: speakerphone state changed.
2938 *
2939 * You <em>cannot</em> receive this through components declared
2940 * in manifests, only by explicitly registering for it with
2941 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2942 * Context.registerReceiver()}.
2943 *
2944 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2945 * speakerphone functionality is enabled or not.
2946 */
2947 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2948 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2949 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2950
2951 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002953 * <p>
2954 * The audio mode encompasses audio routing AND the behavior of
2955 * the telephony layer. Therefore this method should only be used by applications that
2956 * replace the platform-wide management of audio settings or the main telephony application.
2957 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2958 * application when it places a phone call, as it will cause signals from the radio layer
2959 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002961 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 * Informs the HAL about the current audio state so that
2963 * it can route the audio appropriately.
2964 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002965 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002966 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07002968 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002970 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 }
2972 }
2973
2974 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01002975 * This change id controls use of audio modes for call audio redirection.
2976 * @hide
2977 */
2978 @ChangeId
2979 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
2980 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
2981
2982 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 * Returns the current audio mode.
2984 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002985 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002987 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002988 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002989 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002990 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002991 int mode = service.getMode();
2992 int sdk;
2993 try {
2994 sdk = getContext().getApplicationInfo().targetSdkVersion;
2995 } catch (NullPointerException e) {
2996 // some tests don't have a Context
2997 sdk = Build.VERSION.SDK_INT;
2998 }
2999 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3000 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01003001 } else if (mode == MODE_CALL_REDIRECT
3002 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3003 mode = MODE_IN_CALL;
3004 } else if (mode == MODE_COMMUNICATION_REDIRECT
3005 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3006 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003007 }
3008 return mode;
3009 } catch (RemoteException e) {
3010 throw e.rethrowFromSystemServer();
3011 }
3012 }
3013
3014 /**
Nate Myren08635fe2021-04-20 12:04:39 -07003015 * Interface definition of a callback that is notified when the audio mode changes
3016 */
3017 public interface OnModeChangedListener {
3018 /**
3019 * Called on the listener to indicate that the audio mode has changed
3020 *
3021 * @param mode The current audio mode
3022 */
3023 void onModeChanged(@AudioMode int mode);
3024 }
3025
Nate Myren08635fe2021-04-20 12:04:39 -07003026 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003027 * manages the OnModeChangedListener listeners and the ModeDispatcherStub
Nate Myren08635fe2021-04-20 12:04:39 -07003028 */
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003029 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3030 new CallbackUtil.LazyListenerManager();
Nate Myren08635fe2021-04-20 12:04:39 -07003031
Nate Myren08635fe2021-04-20 12:04:39 -07003032
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003033 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3034 implements CallbackUtil.DispatcherStub {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003035
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003036 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08003037 public void register(boolean register) {
3038 try {
3039 if (register) {
3040 getService().registerModeDispatcher(this);
3041 } else {
3042 getService().unregisterModeDispatcher(this);
3043 }
3044 } catch (RemoteException e) {
3045 e.rethrowFromSystemServer();
3046 }
3047 }
Nate Myren08635fe2021-04-20 12:04:39 -07003048
3049 @Override
3050 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003051 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07003052 }
3053 }
3054
Nate Myren08635fe2021-04-20 12:04:39 -07003055 /**
3056 * Adds a listener to be notified of changes to the audio mode.
3057 * See {@link #getMode()}
3058 * @param executor
3059 * @param listener
3060 */
3061 public void addOnModeChangedListener(
3062 @NonNull @CallbackExecutor Executor executor,
3063 @NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003064 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3065 () -> new ModeDispatcherStub());
Nate Myren08635fe2021-04-20 12:04:39 -07003066 }
3067
3068 /**
3069 * Removes a previously added listener for changes to audio mode.
3070 * See {@link #getMode()}
3071 * @param listener
3072 */
3073 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08003074 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
Nate Myren08635fe2021-04-20 12:04:39 -07003075 }
3076
3077 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003078 * Indicates if the platform supports a special call screening and call monitoring mode.
3079 * <p>
3080 * When this mode is supported, it is possible to perform call screening and monitoring
3081 * functions while other use cases like music or movie playback are active.
3082 * <p>
3083 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3084 * call screening mode.
3085 * <p>
3086 * If call screening mode is not supported, setting mode to
3087 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3088 * {@link #getMode()}.
3089 * @return true if call screening mode is supported, false otherwise.
3090 */
3091 public boolean isCallScreeningModeSupported() {
3092 final IAudioService service = getService();
3093 try {
3094 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003096 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 }
3098 }
3099
3100 /* modes for setMode/getMode/setRoute/getRoute */
3101 /**
3102 * Audio harware modes.
3103 */
3104 /**
3105 * Invalid audio mode.
3106 */
3107 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3108 /**
3109 * Current audio mode. Used to apply audio routing to current mode.
3110 */
3111 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3112 /**
3113 * Normal audio mode: not ringing and no call established.
3114 */
3115 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3116 /**
3117 * Ringing audio mode. An incoming is being signaled.
3118 */
3119 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3120 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003121 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122 */
3123 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003124 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003125 * In communication audio mode. An audio/video chat or VoIP call is established.
3126 */
3127 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003128 /**
3129 * Call screening in progress. Call is connected and audio is accessible to call
3130 * screening applications but other audio use cases are still possible.
3131 */
3132 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3133
Eric Laurent1c3408f2021-11-09 12:09:54 +01003134 /**
3135 * A telephony call is established and its audio is being redirected to another device.
3136 */
3137 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3138
3139 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003140 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003141 * device.
3142 */
3143 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3144
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003145 /** @hide */
3146 @IntDef(flag = false, prefix = "MODE_", value = {
3147 MODE_NORMAL,
3148 MODE_RINGTONE,
3149 MODE_IN_CALL,
3150 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003151 MODE_CALL_SCREENING,
3152 MODE_CALL_REDIRECT,
3153 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003154 )
3155 @Retention(RetentionPolicy.SOURCE)
3156 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157
3158 /* Routing bits for setRouting/getRouting API */
3159 /**
3160 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003161 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3162 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 */
Eric Laurenta553c252009-07-17 12:17:14 -07003164 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003165 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003166 * Routing audio output to speaker
3167 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3168 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003169 */
Eric Laurenta553c252009-07-17 12:17:14 -07003170 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 /**
3172 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003173 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3174 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003175 */
3176 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3177 /**
3178 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003179 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3180 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 */
Eric Laurenta553c252009-07-17 12:17:14 -07003182 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 /**
3184 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003185 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3186 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 */
Eric Laurenta553c252009-07-17 12:17:14 -07003188 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189 /**
3190 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003191 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3192 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 */
Eric Laurenta553c252009-07-17 12:17:14 -07003194 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 /**
3196 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003197 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3198 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003199 */
Eric Laurenta553c252009-07-17 12:17:14 -07003200 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201
3202 /**
3203 * Sets the audio routing for a specified mode
3204 *
3205 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3206 * @param routes bit vector of routes requested, created from one or
3207 * more of ROUTE_xxx types. Set bits indicate that route should be on
3208 * @param mask bit vector of routes to change, created from one or more of
3209 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003210 *
3211 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003212 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003213 */
Eric Laurenta553c252009-07-17 12:17:14 -07003214 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003215 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
3217
3218 /**
3219 * Returns the current audio routing bit vector for a specified mode.
3220 *
3221 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3222 * @return an audio route bit vector that can be compared with ROUTE_xxx
3223 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003224 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3225 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003227 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003229 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003230 }
3231
3232 /**
3233 * Checks whether any music is active.
3234 *
3235 * @return true if any music tracks are active.
3236 */
3237 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003238 final IAudioService service = getService();
3239 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003240 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003241 } catch (RemoteException e) {
3242 throw e.rethrowFromSystemServer();
3243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 }
3245
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003246 /**
3247 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003248 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3249 * display). Note that BT audio sinks are not considered remote devices.
3250 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3251 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003252 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003253 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003254 final IAudioService service = getService();
3255 try {
3256 return service.isMusicActive(true /*remotely*/);
3257 } catch (RemoteException e) {
3258 throw e.rethrowFromSystemServer();
3259 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003260 }
3261
3262 /**
3263 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003264 * Checks whether the current audio focus is exclusive.
3265 * @return true if the top of the audio focus stack requested focus
3266 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3267 */
3268 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003269 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003270 try {
3271 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3272 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003273 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003274 }
3275 }
3276
3277 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003278 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003279 * An audio session identifier is a system wide unique identifier for a set of audio streams
3280 * (one or more mixed together).
3281 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3282 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3283 * session ID will be applied to the mixed audio content of the players that share the same
3284 * audio session.
3285 * <p>This method can for instance be used when creating one of the
3286 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3287 * or to specify a session for a speech synthesis utterance
3288 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003289 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003290 * system failed to generate a new session, a condition in which audio playback or recording
3291 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003292 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003293 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003294 int session = AudioSystem.newAudioSessionId();
3295 if (session > 0) {
3296 return session;
3297 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003298 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003299 return ERROR;
3300 }
3301 }
3302
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003303 /**
3304 * A special audio session ID to indicate that the audio session ID isn't known and the
3305 * framework should generate a new value. This can be used when building a new
3306 * {@link AudioTrack} instance with
3307 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3308 */
3309 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3310
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003312 /*
3313 * Sets a generic audio configuration parameter. The use of these parameters
3314 * are platform dependant, see libaudio
3315 *
3316 * ** Temporary interface - DO NOT USE
3317 *
3318 * TODO: Replace with a more generic key:value get/set mechanism
3319 *
3320 * param key name of parameter to set. Must not be null.
3321 * param value value of parameter. Must not be null.
3322 */
3323 /**
3324 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003325 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 */
Eric Laurenta553c252009-07-17 12:17:14 -07003327 @Deprecated public void setParameter(String key, String value) {
3328 setParameters(key+"="+value);
3329 }
3330
3331 /**
3332 * Sets a variable number of parameter values to audio hardware.
3333 *
3334 * @param keyValuePairs list of parameters key value pairs in the form:
3335 * key1=value1;key2=value2;...
3336 *
3337 */
3338 public void setParameters(String keyValuePairs) {
3339 AudioSystem.setParameters(keyValuePairs);
3340 }
3341
3342 /**
William Escandeef429b62021-10-15 18:37:40 +02003343 * @hide
3344 */
3345 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3346 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3347 public void setHfpEnabled(boolean enable) {
3348 AudioSystem.setParameters("hfp_enable=" + enable);
3349 }
3350
3351 /**
3352 * @hide
3353 */
3354 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3355 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3356 public void setHfpVolume(int volume) {
3357 AudioSystem.setParameters("hfp_volume=" + volume);
3358 }
3359
3360 /**
3361 * @hide
3362 */
3363 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3364 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3365 public void setHfpSamplingRate(int rate) {
3366 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3367 }
3368
3369 /**
3370 * @hide
3371 */
3372 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3373 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3374 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3375 boolean hasWbsEnabled) {
3376 AudioSystem.setParameters("bt_headset_name=" + name
3377 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3378 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3379 }
3380
3381 /**
3382 * @hide
3383 */
3384 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3385 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3386 public void setA2dpSuspended(boolean enable) {
3387 AudioSystem.setParameters("A2dpSuspended=" + enable);
3388 }
3389
3390 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003391 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003392 *
3393 * @param keys list of parameters
3394 * @return list of parameters key value pairs in the form:
3395 * key1=value1;key2=value2;...
3396 */
3397 public String getParameters(String keys) {
3398 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003399 }
3400
3401 /* Sound effect identifiers */
3402 /**
3403 * Keyboard and direction pad click sound
3404 * @see #playSoundEffect(int)
3405 */
3406 public static final int FX_KEY_CLICK = 0;
3407 /**
3408 * Focus has moved up
3409 * @see #playSoundEffect(int)
3410 */
3411 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3412 /**
3413 * Focus has moved down
3414 * @see #playSoundEffect(int)
3415 */
3416 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3417 /**
3418 * Focus has moved left
3419 * @see #playSoundEffect(int)
3420 */
3421 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3422 /**
3423 * Focus has moved right
3424 * @see #playSoundEffect(int)
3425 */
3426 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3427 /**
3428 * IME standard keypress sound
3429 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 */
3431 public static final int FX_KEYPRESS_STANDARD = 5;
3432 /**
3433 * IME spacebar keypress sound
3434 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 */
3436 public static final int FX_KEYPRESS_SPACEBAR = 6;
3437 /**
3438 * IME delete keypress sound
3439 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 */
3441 public static final int FX_KEYPRESS_DELETE = 7;
3442 /**
3443 * IME return_keypress sound
3444 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003445 */
3446 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003447
3448 /**
3449 * Invalid keypress sound
3450 * @see #playSoundEffect(int)
3451 */
3452 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003453
3454 /**
3455 * Back sound
3456 * @see #playSoundEffect(int)
3457 */
3458 public static final int FX_BACK = 10;
3459
3460 /**
3461 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003462 * <p>
3463 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3464 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003465 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3466 * @see #playSoundEffect(int)
3467 */
3468 public static final int FX_HOME = 11;
3469
3470 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003471 * @hide Navigation repeat sound 1
3472 * <p>
3473 * To be played by the framework when a focus navigation is repeatedly triggered
3474 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003475 * This is currently only used on TV devices.
3476 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3477 * @see #playSoundEffect(int)
3478 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003479 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003480
3481 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003482 * @hide Navigation repeat sound 2
3483 * <p>
3484 * To be played by the framework when a focus navigation is repeatedly triggered
3485 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003486 * This is currently only used on TV devices.
3487 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3488 * @see #playSoundEffect(int)
3489 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003490 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003491
3492 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003493 * @hide Navigation repeat sound 3
3494 * <p>
3495 * To be played by the framework when a focus navigation is repeatedly triggered
3496 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003497 * This is currently only used on TV devices.
3498 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3499 * @see #playSoundEffect(int)
3500 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003501 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003502
3503 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003504 * @hide Navigation repeat sound 4
3505 * <p>
3506 * To be played by the framework when a focus navigation is repeatedly triggered
3507 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003508 * This is currently only used on TV devices.
3509 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3510 * @see #playSoundEffect(int)
3511 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003512 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 /**
3515 * @hide Number of sound effects
3516 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003517 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003518 public static final int NUM_SOUND_EFFECTS = 16;
3519
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003520 /** @hide */
3521 @IntDef(prefix = { "FX_" }, value = {
3522 FX_KEY_CLICK,
3523 FX_FOCUS_NAVIGATION_UP,
3524 FX_FOCUS_NAVIGATION_DOWN,
3525 FX_FOCUS_NAVIGATION_LEFT,
3526 FX_FOCUS_NAVIGATION_RIGHT,
3527 FX_KEYPRESS_STANDARD,
3528 FX_KEYPRESS_SPACEBAR,
3529 FX_KEYPRESS_DELETE,
3530 FX_KEYPRESS_RETURN,
3531 FX_KEYPRESS_INVALID,
3532 FX_BACK
3533 })
3534 @Retention(RetentionPolicy.SOURCE)
3535 public @interface SystemSoundEffect {}
3536
Philip Junker7f1fdff2020-12-03 16:10:41 +01003537 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003538 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003539 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003540 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003541
3542 /**
3543 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003544 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3545 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003546 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003547 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003548 switch (n) {
3549 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003550 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003551 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003552 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003553 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003554 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003555 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003556 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003557 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003558 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003559 return -1;
3560 }
3561 }
3562
3563 /**
3564 * @hide
3565 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003566 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003567 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003568 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003569 } catch (RemoteException e) {
3570
3571 }
3572 }
3573
3574 /**
3575 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003576 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003577 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003578 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003579 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003580 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003581 } catch (RemoteException e) {
3582 throw e.rethrowFromSystemServer();
3583 }
3584 }
3585
3586 /**
3587 * @hide
3588 * @param enabled
3589 */
3590 public void setHomeSoundEffectEnabled(boolean enabled) {
3591 try {
3592 getService().setHomeSoundEffectEnabled(enabled);
3593 } catch (RemoteException e) {
3594
3595 }
3596 }
3597
3598 /**
3599 * @hide
3600 * @return true if the home sound effect is enabled
3601 */
3602 public boolean isHomeSoundEffectEnabled() {
3603 try {
3604 return getService().isHomeSoundEffectEnabled();
3605 } catch (RemoteException e) {
3606 throw e.rethrowFromSystemServer();
3607 }
3608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609
3610 /**
3611 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003612 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 * NOTE: This version uses the UI settings to determine
3614 * whether sounds are heard or not.
3615 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003616 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003617 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003618 }
3619
3620 /**
3621 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003622 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003623 * @param userId The current user to pull sound settings from
3624 * NOTE: This version uses the UI settings to determine
3625 * whether sounds are heard or not.
3626 * @hide
3627 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003628 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003629 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3630 return;
3631 }
3632
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003633 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003635 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003636 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003637 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003638 }
3639 }
3640
3641 /**
3642 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003643 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003644 * @param volume Sound effect volume.
3645 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3646 * 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 -08003647 * NOTE: This version is for applications that have their own
3648 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003649 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003650 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3652 return;
3653 }
3654
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003655 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 try {
3657 service.playSoundEffectVolume(effectType, volume);
3658 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003659 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660 }
3661 }
3662
3663 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003664 * Load Sound effects.
3665 * This method must be called when sound effects are enabled.
3666 */
3667 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003668 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 try {
3670 service.loadSoundEffects();
3671 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003672 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003673 }
3674 }
3675
3676 /**
3677 * Unload Sound effects.
3678 * This method can be called to free some memory when
3679 * sound effects are disabled.
3680 */
3681 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003682 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 try {
3684 service.unloadSoundEffects();
3685 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003686 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003687 }
3688 }
3689
Eric Laurent4050c932009-07-08 02:52:14 -07003690 /**
Andy Hung69836952020-03-26 01:00:15 -07003691 * @hide
3692 */
3693 public static String audioFocusToString(int focus) {
3694 switch (focus) {
3695 case AUDIOFOCUS_NONE:
3696 return "AUDIOFOCUS_NONE";
3697 case AUDIOFOCUS_GAIN:
3698 return "AUDIOFOCUS_GAIN";
3699 case AUDIOFOCUS_GAIN_TRANSIENT:
3700 return "AUDIOFOCUS_GAIN_TRANSIENT";
3701 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3702 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3703 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3704 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3705 case AUDIOFOCUS_LOSS:
3706 return "AUDIOFOCUS_LOSS";
3707 case AUDIOFOCUS_LOSS_TRANSIENT:
3708 return "AUDIOFOCUS_LOSS_TRANSIENT";
3709 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3710 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3711 default:
3712 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3713 }
3714 }
3715
3716 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003717 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003718 */
3719 public static final int AUDIOFOCUS_NONE = 0;
3720
3721 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003722 * 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 -07003723 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003724 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003725 */
3726 public static final int AUDIOFOCUS_GAIN = 1;
3727 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003728 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3729 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3730 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003731 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003732 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003733 */
3734 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003735 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003736 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003737 * amount of time, and where it is acceptable for other audio applications to keep playing
3738 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003739 * Examples of temporary changes are the playback of driving directions where playback of music
3740 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003741 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003742 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3743 */
3744 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3745 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003746 * Used to indicate a temporary request of audio focus, anticipated to last a short
3747 * amount of time, during which no other applications, or system components, should play
3748 * anything. Examples of exclusive and transient audio focus requests are voice
3749 * memo recording and speech recognition, during which the system shouldn't play any
3750 * notifications, and media playback should have paused.
3751 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3752 */
3753 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3754 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003755 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003756 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003757 */
3758 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3759 /**
3760 * Used to indicate a transient loss of audio focus.
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 = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3764 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003765 * 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 -07003766 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3767 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003768 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003769 */
3770 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3771 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003772
3773 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003774 * Interface definition for a callback to be invoked when the audio focus of the system is
3775 * updated.
3776 */
3777 public interface OnAudioFocusChangeListener {
3778 /**
3779 * Called on the listener to notify it the audio focus for this listener has been changed.
3780 * The focusChange value indicates whether the focus was gained,
3781 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3782 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003783 * When losing focus, listeners can use the focus change information to decide what
3784 * behavior to adopt when losing focus. A music player could for instance elect to lower
3785 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3786 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003787 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003788 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003789 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003790 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003791 }
3792
3793 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003794 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3795 */
3796 private static class FocusRequestInfo {
3797 @NonNull final AudioFocusRequest mRequest;
3798 @Nullable final Handler mHandler;
3799 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3800 mRequest = afr;
3801 mHandler = handler;
3802 }
3803 }
3804
3805 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003806 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3807 * to actual listener objects.
3808 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003809 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003810 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3811 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003812
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003813 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003814 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003815 }
3816
3817 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003818 * Handler for events (audio focus change, recording config change) coming from the
3819 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003820 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003821 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003822 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003823
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003824 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003825 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003826 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003827 private final static int MSSG_FOCUS_CHANGE = 0;
3828 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003829 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003830
3831 /**
3832 * Helper class to handle the forwarding of audio service events to the appropriate listener
3833 */
3834 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003835 private final Handler mHandler;
3836
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003837 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003838 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003839 if (handler == null) {
3840 if ((looper = Looper.myLooper()) == null) {
3841 looper = Looper.getMainLooper();
3842 }
3843 } else {
3844 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003845 }
3846
3847 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003848 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003849 mHandler = new Handler(looper) {
3850 @Override
3851 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003852 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003853 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003854 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3855 if (fri != null) {
3856 final OnAudioFocusChangeListener listener =
3857 fri.mRequest.getOnAudioFocusChangeListener();
3858 if (listener != null) {
3859 Log.d(TAG, "dispatching onAudioFocusChange("
3860 + msg.arg1 + ") to " + msg.obj);
3861 listener.onAudioFocusChange(msg.arg1);
3862 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003863 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003864 } break;
3865 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08003866 final RecordConfigChangeCallbackData cbData =
3867 (RecordConfigChangeCallbackData) msg.obj;
3868 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07003869 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08003870 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003871 } break;
3872 case MSSG_PLAYBACK_CONFIG_CHANGE: {
3873 final PlaybackConfigChangeCallbackData cbData =
3874 (PlaybackConfigChangeCallbackData) msg.obj;
3875 if (cbData.mCb != null) {
3876 if (DEBUG) {
3877 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3878 }
3879 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3880 }
3881 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003882 default:
3883 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003884 }
3885 }
3886 };
3887 } else {
3888 mHandler = null;
3889 }
3890 }
3891
3892 Handler getHandler() {
3893 return mHandler;
3894 }
3895 }
3896
Glenn Kasten30c918c2011-11-10 17:56:41 -08003897 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003898 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003899 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003900 final FocusRequestInfo fri = findFocusRequestInfo(id);
3901 if (fri != null) {
3902 final OnAudioFocusChangeListener listener =
3903 fri.mRequest.getOnAudioFocusChangeListener();
3904 if (listener != null) {
3905 final Handler h = (fri.mHandler == null) ?
3906 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3907 final Message m = h.obtainMessage(
3908 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3909 id/*obj*/);
3910 h.sendMessage(m);
3911 }
3912 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003913 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003914
3915 @Override
3916 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3917 synchronized (mFocusRequestsLock) {
3918 // TODO use generation counter as the key instead
3919 final BlockingFocusResultReceiver focusReceiver =
3920 mFocusRequestsAwaitingResult.remove(clientId);
3921 if (focusReceiver != null) {
3922 focusReceiver.notifyResult(requestResult);
3923 } else {
3924 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3925 }
3926 }
3927 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003928 };
3929
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003930 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003931 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07003932 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003933 } else {
3934 return new String(this.toString() + l.toString());
3935 }
3936 }
3937
3938 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003939 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003940 * Registers a listener to be called when audio focus changes and keeps track of the associated
3941 * focus request (including Handler to use for the listener).
3942 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003943 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003944 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3945 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3946 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3947 new ServiceEventHandlerDelegate(h).getHandler());
3948 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3949 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003950 }
3951
3952 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003953 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003954 * Causes the specified listener to not be called anymore when focus is gained or lost.
3955 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003956 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003957 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003958 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003959 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003960 }
3961
3962
3963 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003964 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003965 */
3966 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3967 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003968 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003969 */
3970 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003971 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003972 * A focus change request whose granting is delayed: the request was successful, but the
3973 * requester will only be granted audio focus once the condition that prevented immediate
3974 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003975 * See {@link #requestAudioFocus(AudioFocusRequest)} and
3976 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003977 */
3978 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003979
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003980 /** @hide */
3981 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3982 AUDIOFOCUS_REQUEST_FAILED,
3983 AUDIOFOCUS_REQUEST_GRANTED,
3984 AUDIOFOCUS_REQUEST_DELAYED }
3985 )
3986 @Retention(RetentionPolicy.SOURCE)
3987 public @interface FocusRequestResult {}
3988
3989 /**
3990 * @hide
3991 * code returned when a synchronous focus request on the client-side is to be blocked
3992 * until the external audio focus policy decides on the response for the client
3993 */
3994 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
3995
3996 /**
3997 * Timeout duration in ms when waiting on an external focus policy for the result for a
3998 * focus request
3999 */
4000 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
4001
4002 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4003
4004 private final Object mFocusRequestsLock = new Object();
4005 /**
4006 * Map of all receivers of focus request results, one per unresolved focus request.
4007 * Receivers are added before sending the request to the external focus policy,
4008 * and are removed either after receiving the result, or after the timeout.
4009 * This variable is lazily initialized.
4010 */
4011 @GuardedBy("mFocusRequestsLock")
4012 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4013
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004014
4015 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004016 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004017 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004018 * @param l the listener to be notified of audio focus changes
4019 * @param streamType the main audio stream type affected by the focus request
4020 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4021 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004022 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07004023 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4024 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07004025 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4026 * that benefits from the system not playing disruptive sounds like notifications, for
4027 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07004028 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004029 * as the playback of a song or a video.
4030 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004031 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004032 */
4033 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004034 PlayerBase.deprecateStreamTypeForPlayback(streamType,
4035 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004036 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004037
4038 try {
4039 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4040 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4041 // AUDIOFOCUS_FLAG_DELAY_OK flag
4042 status = requestAudioFocus(l,
4043 new AudioAttributes.Builder()
4044 .setInternalLegacyStreamType(streamType).build(),
4045 durationHint,
4046 0 /* flags, legacy behavior */);
4047 } catch (IllegalArgumentException e) {
4048 Log.e(TAG, "Audio focus request denied due to ", e);
4049 }
4050
4051 return status;
4052 }
4053
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004054 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004055 /**
4056 * @hide
4057 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4058 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4059 * the system is in a state where focus cannot change, but be granted focus later when
4060 * this condition ends.
4061 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004062 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004063 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004064 /**
4065 * @hide
4066 * Use this flag when requesting audio focus to indicate that the requester
4067 * will pause its media playback (if applicable) when losing audio focus with
4068 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4069 * <br>On some platforms, the ducking may be handled without the application being aware of it
4070 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4071 * content, such as audio book or podcast players, ducking may never be acceptable, and will
4072 * thus always pause. This flag enables them to be declared as such whenever they request focus.
4073 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004074 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004075 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4076 /**
4077 * @hide
4078 * Use this flag to lock audio focus so granting is temporarily disabled.
4079 * <br>This flag can only be used by owners of a registered
4080 * {@link android.media.audiopolicy.AudioPolicy} in
4081 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4082 */
4083 @SystemApi
4084 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004085
4086 /**
4087 * @hide
4088 * flag set on test API calls,
4089 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004090 */
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004091 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004092 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004093 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4094 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004095 /** @hide */
4096 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004097 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004098
4099 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004100 * Request audio focus.
4101 * See the {@link AudioFocusRequest} for information about the options available to configure
4102 * your request, and notification of focus gain and loss.
4103 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4104 * requested.
4105 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4106 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4107 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4108 * is requested without building the {@link AudioFocusRequest} with
4109 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4110 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004111 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004112 */
4113 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004114 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004115 }
4116
4117 /**
4118 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4119 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4120 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4121 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4122 * @throws IllegalArgumentException if passed a null argument
4123 */
4124 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4125 if (focusRequest == null) {
4126 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4127 }
4128 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4129 focusRequest.getAudioAttributes());
4130 }
4131
4132 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004133 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004134 * Request audio focus.
4135 * Send a request to obtain the audio focus. This method differs from
4136 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4137 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004138 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4139 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4140 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4141 * requesting audio focus.
4142 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4143 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4144 * for the playback of driving directions, or notifications sounds.
4145 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4146 * the previous focus owner to keep playing if it ducks its audio output.
4147 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4148 * that benefits from the system not playing disruptive sounds like notifications, for
4149 * usecases such as voice memo recording, or speech recognition.
4150 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4151 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004152 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4153 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004154 * <br>Use 0 when not using any flags for the request, which behaves like
4155 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4156 * focus is granted immediately, or the grant request fails because the system is in a
4157 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004158 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4159 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4160 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4161 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4162 * @throws IllegalArgumentException
4163 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004164 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004165 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004166 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004167 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004168 int durationHint,
4169 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004170 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4171 throw new IllegalArgumentException("Invalid flags 0x"
4172 + Integer.toHexString(flags).toUpperCase());
4173 }
4174 return requestAudioFocus(l, requestAttributes, durationHint,
4175 flags & AUDIOFOCUS_FLAGS_APPS,
4176 null /* no AudioPolicy*/);
4177 }
4178
4179 /**
4180 * @hide
4181 * Request or lock audio focus.
4182 * This method is to be used by system components that have registered an
4183 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4184 * so focus granting is temporarily disabled.
4185 * @param l see the description of the same parameter in
4186 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4187 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4188 * requesting audio focus.
4189 * @param durationHint see the description of the same parameter in
4190 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4191 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004192 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004193 * <br>Use 0 when not using any flags for the request, which behaves like
4194 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4195 * focus is granted immediately, or the grant request fails because the system is in a
4196 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004197 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4198 * focus, or null.
4199 * @return see the description of the same return value in
4200 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4201 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004202 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004203 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004204 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004205 @RequiresPermission(anyOf= {
4206 android.Manifest.permission.MODIFY_PHONE_STATE,
4207 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4208 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004209 public int requestAudioFocus(OnAudioFocusChangeListener l,
4210 @NonNull AudioAttributes requestAttributes,
4211 int durationHint,
4212 int flags,
4213 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004214 // parameter checking
4215 if (requestAttributes == null) {
4216 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4217 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004218 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004219 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004220 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004221 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004222 throw new IllegalArgumentException("Illegal flags 0x"
4223 + Integer.toHexString(flags).toUpperCase());
4224 }
4225 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4226 throw new IllegalArgumentException(
4227 "Illegal null focus listener when flagged as accepting delayed focus grant");
4228 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004229 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4230 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4231 throw new IllegalArgumentException(
4232 "Illegal null focus listener when flagged as pausing instead of ducking");
4233 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004234 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4235 throw new IllegalArgumentException(
4236 "Illegal null audio policy when locking audio focus");
4237 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004238
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004239 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004240 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004241 .setAudioAttributes(requestAttributes)
4242 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4243 == AUDIOFOCUS_FLAG_DELAY_OK)
4244 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4245 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4246 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4247 .build();
4248 return requestAudioFocus(afr, ap);
4249 }
4250
4251 /**
4252 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004253 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4254 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4255 * @param afr the parameters of the request
4256 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4257 * @param clientFakeUid the UID of the client, here an arbitrary int,
4258 * doesn't have to be a real UID
4259 * @param clientTargetSdk the target SDK used by the client
4260 * @return return code indicating status of the request
4261 */
4262 @TestApi
4263 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4264 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4265 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4266 Objects.requireNonNull(afr);
4267 Objects.requireNonNull(clientFakeId);
4268 try {
4269 return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4270 afr.getFocusGain(),
4271 mICallBack,
4272 mAudioFocusDispatcher,
Jean-Michel Trivibec223b2021-12-08 18:40:08 -08004273 clientFakeId, "com.android.test.fakeclient",
4274 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4275 clientFakeUid, clientTargetSdk);
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004276 } catch (RemoteException e) {
4277 throw e.rethrowFromSystemServer();
4278 }
4279 }
4280
4281 /**
4282 * @hide
4283 * Test API to abandon audio focus for an arbitrary client.
4284 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4285 * @param afr the parameters used for the request
4286 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4287 * would be requesting
4288 * @return return code indicating status of the request
4289 */
4290 @TestApi
4291 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4292 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4293 @NonNull String clientFakeId) {
4294 Objects.requireNonNull(afr);
4295 Objects.requireNonNull(clientFakeId);
4296 try {
4297 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4298 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4299 } catch (RemoteException e) {
4300 throw e.rethrowFromSystemServer();
4301 }
4302 }
4303
4304 /**
4305 * @hide
4306 * Return the duration of the fade out applied when a player of the given AudioAttributes
4307 * is losing audio focus
4308 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4309 * @return a duration in ms, 0 indicates no fade out is applied
4310 */
4311 @TestApi
4312 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4313 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4314 {
4315 Objects.requireNonNull(aa);
4316 try {
4317 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4318 } catch (RemoteException e) {
4319 throw e.rethrowFromSystemServer();
4320 }
4321 }
4322
4323 /**
4324 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004325 * Request or lock audio focus.
4326 * This method is to be used by system components that have registered an
4327 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4328 * so focus granting is temporarily disabled.
4329 * @param afr see the description of the same parameter in
4330 * {@link #requestAudioFocus(AudioFocusRequest)}
4331 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4332 * focus, or null.
4333 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4334 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4335 * @throws NullPointerException if the AudioFocusRequest is null
4336 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4337 */
4338 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004339 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004340 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4341 if (afr == null) {
4342 throw new NullPointerException("Illegal null AudioFocusRequest");
4343 }
4344 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4345 if (afr.locksFocus() && ap == null) {
4346 throw new IllegalArgumentException(
4347 "Illegal null audio policy when locking audio focus");
4348 }
4349 registerAudioFocusRequest(afr);
4350 final IAudioService service = getService();
4351 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004352 int sdk;
4353 try {
4354 sdk = getContext().getApplicationInfo().targetSdkVersion;
4355 } catch (NullPointerException e) {
4356 // some tests don't have a Context
4357 sdk = Build.VERSION.SDK_INT;
4358 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004359
4360 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4361 final BlockingFocusResultReceiver focusReceiver;
4362 synchronized (mFocusRequestsLock) {
4363 try {
4364 // TODO status contains result and generation counter for ext policy
4365 status = service.requestAudioFocus(afr.getAudioAttributes(),
4366 afr.getFocusGain(), mICallBack,
4367 mAudioFocusDispatcher,
4368 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004369 getContext().getOpPackageName() /* package name */,
4370 getContext().getAttributionTag(),
4371 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004372 ap != null ? ap.cb() : null,
4373 sdk);
4374 } catch (RemoteException e) {
4375 throw e.rethrowFromSystemServer();
4376 }
4377 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4378 // default path with no external focus policy
4379 return status;
4380 }
4381 if (mFocusRequestsAwaitingResult == null) {
4382 mFocusRequestsAwaitingResult =
4383 new HashMap<String, BlockingFocusResultReceiver>(1);
4384 }
4385 focusReceiver = new BlockingFocusResultReceiver(clientId);
4386 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004387 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004388 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4389 if (DEBUG && !focusReceiver.receivedResult()) {
4390 Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4391 }
4392 synchronized (mFocusRequestsLock) {
4393 mFocusRequestsAwaitingResult.remove(clientId);
4394 }
4395 return focusReceiver.requestResult();
4396 }
4397
4398 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4399 private static final class SafeWaitObject {
4400 private boolean mQuit = false;
4401
4402 public void safeNotify() {
4403 synchronized (this) {
4404 mQuit = true;
4405 this.notify();
4406 }
4407 }
4408
4409 public void safeWait(long millis) throws InterruptedException {
4410 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4411 synchronized (this) {
4412 while (!mQuit) {
4413 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4414 if (timeToWait < 0) { break; }
4415 this.wait(timeToWait);
4416 }
4417 }
4418 }
4419 }
4420
4421 private static final class BlockingFocusResultReceiver {
4422 private final SafeWaitObject mLock = new SafeWaitObject();
4423 @GuardedBy("mLock")
4424 private boolean mResultReceived = false;
4425 // request denied by default (e.g. timeout)
4426 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4427 private final String mFocusClientId;
4428
4429 BlockingFocusResultReceiver(String clientId) {
4430 mFocusClientId = clientId;
4431 }
4432
4433 boolean receivedResult() { return mResultReceived; }
4434 int requestResult() { return mFocusRequestResult; }
4435
4436 void notifyResult(int requestResult) {
4437 synchronized (mLock) {
4438 mResultReceived = true;
4439 mFocusRequestResult = requestResult;
4440 mLock.safeNotify();
4441 }
4442 }
4443
4444 public void waitForResult(long timeOutMs) {
4445 synchronized (mLock) {
4446 if (mResultReceived) {
4447 // the result was received before waiting
4448 return;
4449 }
4450 try {
4451 mLock.safeWait(timeOutMs);
4452 } catch (InterruptedException e) { }
4453 }
4454 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004455 }
4456
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004457 /**
4458 * @hide
4459 * Used internally by telephony package to request audio focus. Will cause the focus request
4460 * to be associated with the "voice communication" identifier only used in AudioService
4461 * to identify this use case.
4462 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4463 * the establishment of the call
4464 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4465 * media applications resume after a call
4466 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004467 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004468 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004469 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004470 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004471 service.requestAudioFocus(new AudioAttributes.Builder()
4472 .setInternalLegacyStreamType(streamType).build(),
4473 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004474 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004475 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004476 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004477 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004478 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004479 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004480 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004481 }
4482 }
4483
4484 /**
4485 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004486 * Return the volume ramping time for a sound to be played after the given focus request,
4487 * and to play a sound of the given attributes
4488 * @param focusGain
4489 * @param attr
4490 * @return
4491 */
4492 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004493 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004494 try {
4495 return service.getFocusRampTimeMs(focusGain, attr);
4496 } catch (RemoteException e) {
4497 throw e.rethrowFromSystemServer();
4498 }
4499 }
4500
4501 /**
4502 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004503 * Set the result to the audio focus request received through
4504 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4505 * @param afi the information about the focus requester
4506 * @param requestResult the result to the focus request to be passed to the requester
4507 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4508 */
4509 @SystemApi
4510 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4511 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4512 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4513 if (afi == null) {
4514 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4515 }
4516 if (ap == null) {
4517 throw new IllegalArgumentException("Illegal null AudioPolicy");
4518 }
4519 final IAudioService service = getService();
4520 try {
4521 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4522 } catch (RemoteException e) {
4523 throw e.rethrowFromSystemServer();
4524 }
4525 }
4526
4527 /**
4528 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004529 * Notifies an application with a focus listener of gain or loss of audio focus.
4530 * This method can only be used by owners of an {@link AudioPolicy} configured with
4531 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4532 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4533 * that was received by the {@code AudioPolicy} through
4534 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4535 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4536 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4537 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4538 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4539 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4540 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4541 * <br>For the focus gain, the change type should be the same as the app requested.
4542 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4543 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4544 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4545 * if there was an error sending the request.
4546 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4547 */
4548 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004549 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004550 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4551 @NonNull AudioPolicy ap) {
4552 if (afi == null) {
4553 throw new NullPointerException("Illegal null AudioFocusInfo");
4554 }
4555 if (ap == null) {
4556 throw new NullPointerException("Illegal null AudioPolicy");
4557 }
4558 final IAudioService service = getService();
4559 try {
4560 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4561 } catch (RemoteException e) {
4562 throw e.rethrowFromSystemServer();
4563 }
4564 }
4565
4566 /**
4567 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004568 * Used internally by telephony package to abandon audio focus, typically after a call or
4569 * when ringing ends and the call is rejected or not answered.
4570 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4571 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004572 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004573 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004574 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004575 try {
John Spurlock61560172015-02-06 19:46:04 -05004576 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004577 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004578 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004579 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004580 }
4581 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004582
4583 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004584 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4585 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004586 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004587 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004588 */
4589 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004590 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4591 }
4592
4593 /**
4594 * @hide
4595 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4596 * @param l the listener with which focus was requested.
4597 * @param aa the {@link AudioAttributes} with which audio focus was requested
4598 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004599 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004600 */
4601 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004602 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4603 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004604 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004605 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004606 unregisterAudioFocusRequest(l);
4607 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004608 try {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004609 status = service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004610 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004611 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004612 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004613 }
4614 return status;
4615 }
4616
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004617 //====================================================================
4618 // Remote Control
4619 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004620 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004621 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4622 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004623 * in the application manifest. The package of the component must match that of
4624 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004625 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004626 */
RoboErikb214efb2014-07-24 13:20:30 -07004627 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004628 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004629 if (eventReceiver == null) {
4630 return;
4631 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004632 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004633 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4634 "receiver and context package names don't match");
4635 return;
4636 }
4637 // construct a PendingIntent for the media button and register it
4638 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4639 // the associated intent will be handled by the component being registered
4640 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004641 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004642 0/*requestCode, ignored*/, mediaButtonIntent,
4643 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004644 registerMediaButtonIntent(pi, eventReceiver);
4645 }
4646
4647 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004648 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4649 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4650 * the buttons to go to any PendingIntent. Note that you should only use this form if
4651 * you know you will continue running for the full time until unregistering the
4652 * PendingIntent.
4653 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004654 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4655 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4656 * media button that was pressed.
4657 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004658 */
RoboErikb214efb2014-07-24 13:20:30 -07004659 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004660 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4661 if (eventReceiver == null) {
4662 return;
4663 }
4664 registerMediaButtonIntent(eventReceiver, null);
4665 }
4666
4667 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004668 * @hide
4669 * no-op if (pi == null) or (eventReceiver == null)
4670 */
4671 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004672 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004673 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4674 return;
4675 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004676 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4677 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004678 }
4679
4680 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004681 * Unregister the receiver of MEDIA_BUTTON intents.
4682 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4683 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004684 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004685 */
RoboErikb214efb2014-07-24 13:20:30 -07004686 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004687 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004688 if (eventReceiver == null) {
4689 return;
4690 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004691 // construct a PendingIntent for the media button and unregister it
4692 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4693 // the associated intent will be handled by the component being registered
4694 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004695 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004696 0/*requestCode, ignored*/, mediaButtonIntent,
4697 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004698 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004699 }
4700
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004701 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004702 * Unregister the receiver of MEDIA_BUTTON intents.
4703 * @param eventReceiver same PendingIntent that was registed with
4704 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004705 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004706 */
RoboErikb214efb2014-07-24 13:20:30 -07004707 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004708 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4709 if (eventReceiver == null) {
4710 return;
4711 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004712 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004713 }
4714
4715 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004716 * @hide
4717 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004718 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004719 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004720 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004721 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004722
4723 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004724 * Registers the remote control client for providing information to display on the remote
4725 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004726 * @param rcClient The remote control client from which remote controls will receive
4727 * information to display.
4728 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004729 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004730 */
RoboErikb214efb2014-07-24 13:20:30 -07004731 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004732 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004733 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004734 return;
4735 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004736 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004737 }
4738
4739 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004740 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004741 * remote controls.
4742 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004743 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004744 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004745 */
RoboErikb214efb2014-07-24 13:20:30 -07004746 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004747 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004748 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004749 return;
4750 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004751 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004752 }
4753
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004754 /**
RoboErika66c40b2014-08-15 15:21:41 -07004755 * Registers a {@link RemoteController} instance for it to receive media
4756 * metadata updates and playback state information from applications using
4757 * {@link RemoteControlClient}, and control their playback.
4758 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004759 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004760 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004761 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004762 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004763 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004764 * @return true if the {@link RemoteController} was successfully registered,
4765 * false if an error occurred, due to an internal system error, or
4766 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004767 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004768 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4769 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004770 */
RoboErikb214efb2014-07-24 13:20:30 -07004771 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004772 public boolean registerRemoteController(RemoteController rctlr) {
4773 if (rctlr == null) {
4774 return false;
4775 }
RoboErik430fc482014-06-12 15:49:20 -07004776 rctlr.startListeningToSessions();
4777 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004778 }
4779
4780 /**
RoboErika66c40b2014-08-15 15:21:41 -07004781 * Unregisters a {@link RemoteController}, causing it to no longer receive
4782 * media metadata and playback state information, and no longer be capable
4783 * of controlling playback.
4784 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004785 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004786 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004787 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4788 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004789 */
RoboErikb214efb2014-07-24 13:20:30 -07004790 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004791 public void unregisterRemoteController(RemoteController rctlr) {
4792 if (rctlr == null) {
4793 return;
4794 }
RoboErik430fc482014-06-12 15:49:20 -07004795 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004796 }
4797
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004798
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004799 //====================================================================
4800 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004801 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004802 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004803 * Register the given {@link AudioPolicy}.
4804 * This call is synchronous and blocks until the registration process successfully completed
4805 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004806 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004807 * @return {@link #ERROR} if there was an error communicating with the registration service
4808 * or if the user doesn't have the required
4809 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4810 * {@link #SUCCESS} otherwise.
4811 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004812 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004813 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004814 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004815 return registerAudioPolicyStatic(policy);
4816 }
4817
4818 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004819 if (policy == null) {
4820 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4821 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004822 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004823 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004824 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004825 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07004826 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4827 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004828 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004829 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004830 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004831 } else {
4832 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004833 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004834 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004835 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004836 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004837 }
4838 return SUCCESS;
4839 }
4840
4841 /**
4842 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004843 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004844 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004845 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004846 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004847 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004848 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004849 unregisterAudioPolicyAsyncStatic(policy);
4850 }
4851
4852 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004853 if (policy == null) {
4854 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4855 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004856 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004857 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004858 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004859 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004860 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004861 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004862 }
4863 }
4864
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004865 /**
4866 * @hide
4867 * Unregisters an {@link AudioPolicy} synchronously.
4868 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4869 * associated with mixes of this policy.
4870 * @param policy the non-null {@link AudioPolicy} to unregister.
4871 */
4872 @SystemApi
4873 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4874 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4875 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4876 final IAudioService service = getService();
4877 try {
4878 policy.invalidateCaptorsAndInjectors();
4879 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004880 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004881 } catch (RemoteException e) {
4882 throw e.rethrowFromSystemServer();
4883 }
4884 }
4885
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07004886 /**
4887 * @hide
4888 * @return true if an AudioPolicy was previously registered
4889 */
4890 @TestApi
4891 public boolean hasRegisteredDynamicPolicy() {
4892 final IAudioService service = getService();
4893 try {
4894 return service.hasRegisteredDynamicPolicy();
4895 } catch (RemoteException e) {
4896 throw e.rethrowFromSystemServer();
4897 }
4898 }
4899
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004900 //====================================================================
4901 // Notification of playback activity & playback configuration
4902 /**
4903 * Interface for receiving update notifications about the playback activity on the system.
4904 * Extend this abstract class and register it with
4905 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4906 * to be notified.
4907 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4908 * configuration.
4909 * @see AudioPlaybackConfiguration
4910 */
4911 public static abstract class AudioPlaybackCallback {
4912 /**
4913 * Called whenever the playback activity and configuration has changed.
4914 * @param configs list containing the results of
4915 * {@link AudioManager#getActivePlaybackConfigurations()}.
4916 */
4917 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4918 }
4919
4920 private static class AudioPlaybackCallbackInfo {
4921 final AudioPlaybackCallback mCb;
4922 final Handler mHandler;
4923 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4924 mCb = cb;
4925 mHandler = handler;
4926 }
4927 }
4928
4929 private final static class PlaybackConfigChangeCallbackData {
4930 final AudioPlaybackCallback mCb;
4931 final List<AudioPlaybackConfiguration> mConfigs;
4932
4933 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4934 List<AudioPlaybackConfiguration> configs) {
4935 mCb = cb;
4936 mConfigs = configs;
4937 }
4938 }
4939
4940 /**
4941 * Register a callback to be notified of audio playback changes through
4942 * {@link AudioPlaybackCallback}
4943 * @param cb non-null callback to register
4944 * @param handler the {@link Handler} object for the thread on which to execute
4945 * the callback. If <code>null</code>, the {@link Handler} associated with the main
4946 * {@link Looper} will be used.
4947 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08004948 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4949 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004950 {
4951 if (cb == null) {
4952 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4953 }
4954
4955 synchronized(mPlaybackCallbackLock) {
4956 // lazy initialization of the list of playback callbacks
4957 if (mPlaybackCallbackList == null) {
4958 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4959 }
4960 final int oldCbCount = mPlaybackCallbackList.size();
4961 if (!hasPlaybackCallback_sync(cb)) {
4962 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4963 new ServiceEventHandlerDelegate(handler).getHandler()));
4964 final int newCbCount = mPlaybackCallbackList.size();
4965 if ((oldCbCount == 0) && (newCbCount > 0)) {
4966 // register binder for callbacks
4967 try {
4968 getService().registerPlaybackCallback(mPlayCb);
4969 } catch (RemoteException e) {
4970 throw e.rethrowFromSystemServer();
4971 }
4972 }
4973 } else {
4974 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4975 + "registered callback");
4976 }
4977 }
4978 }
4979
4980 /**
4981 * Unregister an audio playback callback previously registered with
4982 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4983 * @param cb non-null callback to unregister
4984 */
4985 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4986 if (cb == null) {
4987 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4988 }
4989 synchronized(mPlaybackCallbackLock) {
4990 if (mPlaybackCallbackList == null) {
4991 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4992 + " that was never registered");
4993 return;
4994 }
4995 final int oldCbCount = mPlaybackCallbackList.size();
4996 if (removePlaybackCallback_sync(cb)) {
4997 final int newCbCount = mPlaybackCallbackList.size();
4998 if ((oldCbCount > 0) && (newCbCount == 0)) {
4999 // unregister binder for callbacks
5000 try {
5001 getService().unregisterPlaybackCallback(mPlayCb);
5002 } catch (RemoteException e) {
5003 throw e.rethrowFromSystemServer();
5004 }
5005 }
5006 } else {
5007 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5008 + " already unregistered or never registered");
5009 }
5010 }
5011 }
5012
5013 /**
5014 * Returns the current active audio playback configurations of the device
5015 * @return a non-null list of playback configurations. An empty list indicates there is no
5016 * playback active when queried.
5017 * @see AudioPlaybackConfiguration
5018 */
5019 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5020 final IAudioService service = getService();
5021 try {
5022 return service.getActivePlaybackConfigurations();
5023 } catch (RemoteException e) {
5024 throw e.rethrowFromSystemServer();
5025 }
5026 }
5027
5028 /**
5029 * All operations on this list are sync'd on mPlaybackCallbackLock.
5030 * List is lazy-initialized in
5031 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5032 * List can be null.
5033 */
5034 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5035 private final Object mPlaybackCallbackLock = new Object();
5036
5037 /**
5038 * Must be called synchronized on mPlaybackCallbackLock
5039 */
5040 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5041 if (mPlaybackCallbackList != null) {
5042 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5043 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5044 return true;
5045 }
5046 }
5047 }
5048 return false;
5049 }
5050
5051 /**
5052 * Must be called synchronized on mPlaybackCallbackLock
5053 */
5054 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5055 if (mPlaybackCallbackList != null) {
5056 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5057 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5058 mPlaybackCallbackList.remove(i);
5059 return true;
5060 }
5061 }
5062 }
5063 return false;
5064 }
5065
5066 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005067 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07005068 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5069 boolean flush) {
5070 if (flush) {
5071 Binder.flushPendingCommands();
5072 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005073 synchronized(mPlaybackCallbackLock) {
5074 if (mPlaybackCallbackList != null) {
5075 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5076 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5077 if (arci.mHandler != null) {
5078 final Message m = arci.mHandler.obtainMessage(
5079 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5080 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5081 arci.mHandler.sendMessage(m);
5082 }
5083 }
5084 }
5085 }
5086 }
5087
5088 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005089
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005090 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005091 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005092 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005093 * Interface for receiving update notifications about the recording configuration. Extend
5094 * this abstract class and register it with
5095 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5096 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005097 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5098 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005099 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005100 */
5101 public static abstract class AudioRecordingCallback {
5102 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005103 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005104 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005105 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005106 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005107 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005108 }
5109
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005110 private static class AudioRecordingCallbackInfo {
5111 final AudioRecordingCallback mCb;
5112 final Handler mHandler;
5113 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5114 mCb = cb;
5115 mHandler = handler;
5116 }
5117 }
5118
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005119 private final static class RecordConfigChangeCallbackData {
5120 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005121 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005122
5123 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005124 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005125 mCb = cb;
5126 mConfigs = configs;
5127 }
5128 }
5129
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005130 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005131 * Register a callback to be notified of audio recording changes through
5132 * {@link AudioRecordingCallback}
5133 * @param cb non-null callback to register
5134 * @param handler the {@link Handler} object for the thread on which to execute
5135 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5136 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005137 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005138 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5139 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005140 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005141 if (cb == null) {
5142 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5143 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005144
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005145 synchronized(mRecordCallbackLock) {
5146 // lazy initialization of the list of recording callbacks
5147 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005148 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005149 }
5150 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005151 if (!hasRecordCallback_sync(cb)) {
5152 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5153 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005154 final int newCbCount = mRecordCallbackList.size();
5155 if ((oldCbCount == 0) && (newCbCount > 0)) {
5156 // register binder for callbacks
5157 final IAudioService service = getService();
5158 try {
5159 service.registerRecordingCallback(mRecCb);
5160 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005161 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005162 }
5163 }
5164 } else {
5165 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5166 + "registered callback");
5167 }
5168 }
5169 }
5170
5171 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005172 * Unregister an audio recording callback previously registered with
5173 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5174 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005175 */
5176 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5177 if (cb == null) {
5178 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5179 }
5180 synchronized(mRecordCallbackLock) {
5181 if (mRecordCallbackList == null) {
5182 return;
5183 }
5184 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005185 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005186 final int newCbCount = mRecordCallbackList.size();
5187 if ((oldCbCount > 0) && (newCbCount == 0)) {
5188 // unregister binder for callbacks
5189 final IAudioService service = getService();
5190 try {
5191 service.unregisterRecordingCallback(mRecCb);
5192 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005193 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005194 }
5195 }
5196 } else {
5197 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5198 + " already unregistered or never registered");
5199 }
5200 }
5201 }
5202
5203 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005204 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005205 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005206 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005207 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005208 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005209 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005210 final IAudioService service = getService();
5211 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005212 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005213 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005214 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005215 }
5216 }
5217
5218 /**
5219 * constants for the recording events, to keep in sync
5220 * with frameworks/av/include/media/AudioPolicy.h
5221 */
5222 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005223 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005224 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005225 public static final int RECORD_CONFIG_EVENT_START = 0;
5226 /** @hide */
5227 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5228 /** @hide */
5229 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5230 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005231 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005232 /**
5233 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5234 */
5235 /** @hide */
5236 public static final int RECORD_RIID_INVALID = -1;
5237 /** @hide */
5238 public static final int RECORDER_STATE_STARTED = 0;
5239 /** @hide */
5240 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005241
5242 /**
5243 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005244 * List is lazy-initialized in
5245 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005246 * List can be null.
5247 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005248 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005249 private final Object mRecordCallbackLock = new Object();
5250
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005251 /**
5252 * Must be called synchronized on mRecordCallbackLock
5253 */
5254 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5255 if (mRecordCallbackList != null) {
5256 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5257 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5258 return true;
5259 }
5260 }
5261 }
5262 return false;
5263 }
5264
5265 /**
5266 * Must be called synchronized on mRecordCallbackLock
5267 */
5268 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5269 if (mRecordCallbackList != null) {
5270 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5271 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5272 mRecordCallbackList.remove(i);
5273 return true;
5274 }
5275 }
5276 }
5277 return false;
5278 }
5279
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005280 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005281 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005282 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005283 synchronized(mRecordCallbackLock) {
5284 if (mRecordCallbackList != null) {
5285 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5286 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5287 if (arci.mHandler != null) {
5288 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005289 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5290 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005291 arci.mHandler.sendMessage(m);
5292 }
5293 }
5294 }
5295 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005296 }
5297
5298 };
5299
5300 //=====================================================================
5301
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005302 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005303 * @hide
5304 * Reload audio settings. This method is called by Settings backup
5305 * agent when audio settings are restored and causes the AudioService
5306 * to read and apply restored settings.
5307 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005308 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005309 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005310 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005311 try {
5312 service.reloadAudioSettings();
5313 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005314 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005315 }
5316 }
5317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005318 /**
5319 * {@hide}
5320 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005321 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005322
5323 /**
5324 * Checks whether the phone is in silent mode, with or without vibrate.
5325 *
5326 * @return true if phone is in silent mode, with or without vibrate.
5327 *
5328 * @see #getRingerMode()
5329 *
5330 * @hide pending API Council approval
5331 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005332 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005333 public boolean isSilentMode() {
5334 int ringerMode = getRingerMode();
5335 boolean silentMode =
5336 (ringerMode == RINGER_MODE_SILENT) ||
5337 (ringerMode == RINGER_MODE_VIBRATE);
5338 return silentMode;
5339 }
5340
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005341 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5342 // class is not used by other parts of the framework, which instead use definitions and methods
5343 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5344
Eric Laurent948d3272014-05-16 15:18:45 -07005345 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005346 * The audio device code for representing "no device." */
5347 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5348 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005349 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005350 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5351 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5352 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5353 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005354 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005355 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005356 /** @hide
5357 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005358 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005359 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005360 /** @hide
5361 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005362 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005363 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005364 /** @hide
5365 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005366 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005367 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005368 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005369 * The audio output device code for a USB headphone with attached microphone */
5370 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5371 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005372 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005373 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005374 /** @hide
5375 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5376 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005377 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005378 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005379 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5380 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005381 /** @hide
5382 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005383 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5384 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005385 /** @hide
5386 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005387 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005388 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005389 /** @hide
5390 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005391 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005392 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5393 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005394 /** @hide
5395 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005396 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005397 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5398 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005399 /** @hide
5400 * The audio output device code for S/PDIF (legacy) or HDMI
5401 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005402 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005403 /** @hide
5404 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005405 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005406 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5407 /** @hide
5408 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005409 * docking station
5410 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005411 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005412 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005413 /** @hide
5414 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005415 * docking station
5416 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005417 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005418 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005419 /** @hide
5420 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005421 * mode and the Android device in USB device mode
5422 */
5423 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005424 /** @hide
5425 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005426 * mode and the Android device in USB host mode
5427 */
5428 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005429 /** @hide
5430 * The audio output device code for projection output.
5431 */
5432 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5433 /** @hide
5434 * The audio output device code the telephony voice TX path.
5435 */
5436 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5437 /** @hide
5438 * The audio output device code for an analog jack with line impedance detected.
5439 */
5440 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5441 /** @hide
5442 * The audio output device code for HDMI Audio Return Channel.
5443 */
5444 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5445 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005446 * The audio output device code for HDMI enhanced Audio Return Channel.
5447 */
5448 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5449 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005450 * The audio output device code for S/PDIF digital connection.
5451 */
5452 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5453 /** @hide
5454 * The audio output device code for built-in FM transmitter.
5455 */
5456 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5457 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005458 * The audio output device code for echo reference injection point.
5459 */
5460 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5461 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005462 * The audio output device code for a BLE audio headset.
5463 */
5464 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5465 /** @hide
5466 * The audio output device code for a BLE audio speaker.
5467 */
5468 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5469 /** @hide
Eric Laurent277373e2022-01-20 14:42:22 +01005470 * The audio output device code for a BLE audio brodcast group.
5471 */
5472 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
5473 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005474 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005475 * used in the future in a set method to select whatever default device is chosen by the
5476 * platform-specific implementation.
5477 */
5478 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5479
Eric Laurent948d3272014-05-16 15:18:45 -07005480 /** @hide
5481 * The audio input device code for default built-in microphone
5482 */
5483 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5484 /** @hide
5485 * The audio input device code for a Bluetooth SCO headset
5486 */
5487 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5488 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5489 /** @hide
5490 * The audio input device code for wired headset microphone
5491 */
5492 public static final int DEVICE_IN_WIRED_HEADSET =
5493 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5494 /** @hide
5495 * The audio input device code for HDMI
5496 */
5497 public static final int DEVICE_IN_HDMI =
5498 AudioSystem.DEVICE_IN_HDMI;
5499 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005500 * The audio input device code for HDMI ARC
5501 */
5502 public static final int DEVICE_IN_HDMI_ARC =
5503 AudioSystem.DEVICE_IN_HDMI_ARC;
5504
5505 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005506 * The audio input device code for HDMI EARC
5507 */
5508 public static final int DEVICE_IN_HDMI_EARC =
5509 AudioSystem.DEVICE_IN_HDMI_EARC;
5510
5511 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005512 * The audio input device code for telephony voice RX path
5513 */
5514 public static final int DEVICE_IN_TELEPHONY_RX =
5515 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5516 /** @hide
5517 * The audio input device code for built-in microphone pointing to the back
5518 */
5519 public static final int DEVICE_IN_BACK_MIC =
5520 AudioSystem.DEVICE_IN_BACK_MIC;
5521 /** @hide
5522 * The audio input device code for analog from a docking station
5523 */
5524 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5525 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5526 /** @hide
5527 * The audio input device code for digital from a docking station
5528 */
5529 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5530 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5531 /** @hide
5532 * The audio input device code for a USB audio accessory. The accessory is in USB host
5533 * mode and the Android device in USB device mode
5534 */
5535 public static final int DEVICE_IN_USB_ACCESSORY =
5536 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5537 /** @hide
5538 * The audio input device code for a USB audio device. The device is in USB device
5539 * mode and the Android device in USB host mode
5540 */
5541 public static final int DEVICE_IN_USB_DEVICE =
5542 AudioSystem.DEVICE_IN_USB_DEVICE;
5543 /** @hide
5544 * The audio input device code for a FM radio tuner
5545 */
5546 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5547 /** @hide
5548 * The audio input device code for a TV tuner
5549 */
5550 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5551 /** @hide
5552 * The audio input device code for an analog jack with line impedance detected
5553 */
5554 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5555 /** @hide
5556 * The audio input device code for a S/PDIF digital connection
5557 */
5558 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005559 /** @hide
5560 * The audio input device code for audio loopback
5561 */
5562 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005563 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005564 * The audio input device code for an echo reference capture point.
5565 */
5566 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5567 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005568 * The audio input device code for a BLE audio headset.
5569 */
5570 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005571
5572 /**
5573 * Return true if the device code corresponds to an output device.
5574 * @hide
5575 */
5576 public static boolean isOutputDevice(int device)
5577 {
5578 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5579 }
5580
5581 /**
5582 * Return true if the device code corresponds to an input device.
5583 * @hide
5584 */
5585 public static boolean isInputDevice(int device)
5586 {
5587 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5588 }
5589
5590
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005591 /**
5592 * Return the enabled devices for the specified output stream type.
5593 *
5594 * @param streamType The stream type to query. One of
5595 * {@link #STREAM_VOICE_CALL},
5596 * {@link #STREAM_SYSTEM},
5597 * {@link #STREAM_RING},
5598 * {@link #STREAM_MUSIC},
5599 * {@link #STREAM_ALARM},
5600 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005601 * {@link #STREAM_DTMF},
5602 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005603 *
5604 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5605 * stream. Zero or more of
5606 * {@link #DEVICE_OUT_EARPIECE},
5607 * {@link #DEVICE_OUT_SPEAKER},
5608 * {@link #DEVICE_OUT_WIRED_HEADSET},
5609 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5610 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5611 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5612 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5613 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5614 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5615 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005616 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005617 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5618 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005619 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5620 * {@link #DEVICE_OUT_USB_DEVICE}.
5621 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5622 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5623 * {@link #DEVICE_OUT_LINE}.
5624 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005625 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005626 * {@link #DEVICE_OUT_SPDIF}.
5627 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005628 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5629 *
5630 * The implementation may support additional device codes beyond those listed, so
5631 * the application should ignore any bits which it does not recognize.
5632 * Note that the information may be imprecise when the implementation
5633 * cannot distinguish whether a particular device is enabled.
5634 *
Andy Hungb11e4c72021-04-13 19:31:00 -07005635 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
5636 * will have multi-bit device types.
5637 * Prefer to use {@link #getDevicesForAttributes()} instead,
5638 * noting that getDevicesForStream() has a few small discrepancies
5639 * for better volume handling.
5640 * @hide
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005641 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005642 @UnsupportedAppUsage
Andy Hungb11e4c72021-04-13 19:31:00 -07005643 @Deprecated
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005644 public int getDevicesForStream(int streamType) {
5645 switch (streamType) {
Andy Hungb11e4c72021-04-13 19:31:00 -07005646 case STREAM_VOICE_CALL:
5647 case STREAM_SYSTEM:
5648 case STREAM_RING:
5649 case STREAM_MUSIC:
5650 case STREAM_ALARM:
5651 case STREAM_NOTIFICATION:
5652 case STREAM_DTMF:
5653 case STREAM_ACCESSIBILITY:
5654 final IAudioService service = getService();
5655 try {
5656 return service.getDeviceMaskForStream(streamType);
5657 } catch (RemoteException e) {
5658 throw e.rethrowFromSystemServer();
5659 }
5660 default:
5661 return 0;
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005662 }
5663 }
5664
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005665 /**
5666 * @hide
5667 * Get the audio devices that would be used for the routing of the given audio attributes.
5668 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5669 * @return an empty list if there was an issue with the request, a list of audio devices
5670 * otherwise (typically one device, except for duplicated paths).
5671 */
5672 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005673 @RequiresPermission(anyOf = {
5674 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5675 android.Manifest.permission.QUERY_AUDIO_STATE
5676 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005677 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005678 @NonNull AudioAttributes attributes) {
5679 Objects.requireNonNull(attributes);
5680 final IAudioService service = getService();
5681 try {
5682 return service.getDevicesForAttributes(attributes);
5683 } catch (RemoteException e) {
5684 throw e.rethrowFromSystemServer();
5685 }
5686 }
5687
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005688 /**
Dorin Drimusdaeb6a92021-12-22 11:46:26 +01005689 * Get the audio devices that would be used for the routing of the given audio attributes.
5690 * These are the devices anticipated to play sound from an {@link AudioTrack} created with
5691 * the specified {@link AudioAttributes}.
5692 * The audio routing can change if audio devices are physically connected or disconnected or
5693 * concurrently through {@link AudioRouting} or {@link MediaRouter}.
5694 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5695 * @return an empty list if there was an issue with the request, a list of
5696 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
5697 */
5698 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
5699 @NonNull AudioAttributes attributes) {
5700 final List<AudioDeviceAttributes> devicesForAttributes;
5701 try {
5702 Objects.requireNonNull(attributes);
5703 final IAudioService service = getService();
5704 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
5705 } catch (Exception e) {
5706 Log.i(TAG, "No audio devices available for specified attributes.");
5707 return Collections.emptyList();
5708 }
5709
5710 // Map from AudioDeviceAttributes to AudioDeviceInfo
5711 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
5712 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
5713 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
5714 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
5715 if (deviceForAttributes.getType() == deviceInfo.getType()
5716 && TextUtils.equals(deviceForAttributes.getAddress(),
5717 deviceInfo.getAddress())) {
5718 deviceInfosForAttributes.add(deviceInfo);
5719 }
5720 }
5721 }
5722 return Collections.unmodifiableList(deviceInfosForAttributes);
5723 }
5724
5725 /**
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005726 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005727 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02005728 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5729 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005730 */
5731 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5732 /**
5733 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005734 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02005735 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005736 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005737 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005738 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5739 /**
5740 * @hide
5741 * Volume behavior for an audio device where the volume is always set to provide no attenuation
5742 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005743 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005744 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005745 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005746 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5747 /**
5748 * @hide
5749 * Volume behavior for an audio device where the volume is either set to muted, or to provide
5750 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005751 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005752 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005753 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005754 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5755 /**
5756 * @hide
5757 * Volume behavior for an audio device where no software attenuation is applied, and
5758 * the volume is kept synchronized between the host and the device itself through a
5759 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005760 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005761 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005762 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005763 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5764 /**
5765 * @hide
5766 * Volume behavior for an audio device where no software attenuation is applied, and
5767 * the volume is kept synchronized between the host and the device itself through a
5768 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5769 * normal vs in phone call).
5770 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02005771 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005772 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005773 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005774 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5775
5776 /** @hide */
5777 @IntDef({
5778 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5779 DEVICE_VOLUME_BEHAVIOR_FULL,
5780 DEVICE_VOLUME_BEHAVIOR_FIXED,
5781 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5782 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5783 })
5784 @Retention(RetentionPolicy.SOURCE)
5785 public @interface DeviceVolumeBehavior {}
5786
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005787 /** @hide */
5788 @IntDef({
5789 DEVICE_VOLUME_BEHAVIOR_UNSET,
5790 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5791 DEVICE_VOLUME_BEHAVIOR_FULL,
5792 DEVICE_VOLUME_BEHAVIOR_FIXED,
5793 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5794 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5795 })
5796 @Retention(RetentionPolicy.SOURCE)
5797 public @interface DeviceVolumeBehaviorState {}
5798
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005799 /**
5800 * @hide
5801 * Throws IAE on an invalid volume behavior value
5802 * @param volumeBehavior behavior value to check
5803 */
5804 public static void enforceValidVolumeBehavior(int volumeBehavior) {
5805 switch (volumeBehavior) {
5806 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5807 case DEVICE_VOLUME_BEHAVIOR_FULL:
5808 case DEVICE_VOLUME_BEHAVIOR_FIXED:
5809 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5810 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5811 return;
5812 default:
5813 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5814 }
5815 }
5816
5817 /**
5818 * @hide
5819 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005820 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5821 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5822 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5823 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5824 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5825 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005826 * @param deviceVolumeBehavior one of the device behaviors
5827 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005828 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005829 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5830 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5831 @DeviceVolumeBehavior int deviceVolumeBehavior) {
5832 // verify arguments (validity of device type is enforced in server)
5833 Objects.requireNonNull(device);
5834 enforceValidVolumeBehavior(deviceVolumeBehavior);
5835 // communicate with service
5836 final IAudioService service = getService();
5837 try {
5838 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5839 mApplicationContext.getOpPackageName());
5840 } catch (RemoteException e) {
5841 throw e.rethrowFromSystemServer();
5842 }
5843 }
5844
5845 /**
5846 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005847 * Returns the volume device behavior for the given audio device
5848 * @param device the audio device
5849 * @return the volume behavior for the device
5850 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005851 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005852 @RequiresPermission(anyOf = {
5853 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5854 android.Manifest.permission.QUERY_AUDIO_STATE
5855 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02005856 public @DeviceVolumeBehavior
5857 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005858 // verify arguments (validity of device type is enforced in server)
5859 Objects.requireNonNull(device);
5860 // communicate with service
5861 final IAudioService service = getService();
5862 try {
5863 return service.getDeviceVolumeBehavior(device);
5864 } catch (RemoteException e) {
5865 throw e.rethrowFromSystemServer();
5866 }
5867 }
5868
kholoud mohamed37839212021-03-15 16:49:06 +00005869 /**
5870 * @hide
5871 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5872 */
5873 @TestApi
5874 @RequiresPermission(anyOf = {
5875 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5876 android.Manifest.permission.QUERY_AUDIO_STATE
5877 })
5878 public boolean isFullVolumeDevice() {
5879 final AudioAttributes attributes = new AudioAttributes.Builder()
5880 .setUsage(AudioAttributes.USAGE_MEDIA)
5881 .build();
5882 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5883 for (AudioDeviceAttributes device : devices) {
5884 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5885 return true;
5886 }
5887 }
5888 return false;
5889 }
5890
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005891 /**
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005892 * Indicate wired accessory connection state change.
5893 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5894 * @param state new connection state: 1 connected, 0 disconnected
5895 * @param name device name
5896 * {@hide}
5897 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005898 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07005899 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Nathalie Le Clair7b72c392022-04-04 13:25:46 +02005900 public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
5901 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005902 setWiredDeviceConnectionState(attributes, state);
5903 }
5904
5905 /**
5906 * Indicate wired accessory connection state change and attributes.
5907 * @param state new connection state: 1 connected, 0 disconnected
5908 * @param attributes attributes of the connected device
5909 * {@hide}
5910 */
5911 @UnsupportedAppUsage
5912 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5913 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005914 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005915 try {
Nathalie Le Clair517a1322021-10-15 14:22:41 +02005916 service.setWiredDeviceConnectionState(attributes, state,
Marco Nelissena80ac052015-03-12 16:17:45 -07005917 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005918 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005919 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005920 }
5921 }
5922
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00005923 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08005924 * Indicate wired accessory connection state change.
5925 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
5926 * @param connected true for connected, false for disconnected
5927 * {@hide}
5928 */
5929 @TestApi
5930 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5931 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
5932 boolean connected) {
5933 try {
5934 getService().setTestDeviceConnectionState(device, connected);
5935 } catch (RemoteException e) {
5936 throw e.rethrowFromSystemServer();
5937 }
5938 }
5939
5940 /**
wescande7c17ba0c2021-07-30 16:46:14 +02005941 * Indicate Bluetooth profile connection state change.
5942 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
5943 * <code>previousDevice</code>
5944 * This operation is asynchronous.
5945 *
5946 * @param newDevice Bluetooth device connected or null if there is no new devices
5947 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
5948 * devices
William Escandeac11d772022-01-25 18:01:15 +01005949 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005950 * {@hide}
5951 */
wescande7c17ba0c2021-07-30 16:46:14 +02005952 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5953 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
5954 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
William Escandeac11d772022-01-25 18:01:15 +01005955 @Nullable BluetoothDevice previousDevice,
5956 @NonNull BluetoothProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005957 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005958 try {
wescande7c17ba0c2021-07-30 16:46:14 +02005959 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005960 } catch (RemoteException e) {
5961 throw e.rethrowFromSystemServer();
5962 }
5963 }
5964
Jeff Sharkey098d5802012-04-26 17:30:34 -07005965 /** {@hide} */
5966 public IRingtonePlayer getRingtonePlayer() {
5967 try {
5968 return getService().getRingtonePlayer();
5969 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005970 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005971 }
5972 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005973
5974 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005975 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07005976 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
5977 * should use this value as a default, and offer the user the option to override it.
5978 * The low latency output stream is typically either the device's primary output stream,
5979 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005980 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005981 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005982 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5983 "android.media.property.OUTPUT_SAMPLE_RATE";
5984
5985 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005986 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07005987 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
5988 * should use this value as a minimum, and offer the user the option to override it.
5989 * The low latency output stream is typically either the device's primary output stream,
5990 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005991 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005992 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005993 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
5994 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
5995
5996 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07005997 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
5998 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5999 */
6000 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6001 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6002
6003 /**
6004 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6005 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6006 */
6007 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6008 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6009
6010 /**
ragoa7cc59c2015-12-02 11:31:15 -08006011 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6012 * available and supported with the expected frequency range and level response.
6013 */
6014 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6015 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6016 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07006017 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006018 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07006019 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6020 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08006021 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6022 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6023 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07006024 * @return A string representing the associated value for that property key,
6025 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07006026 */
6027 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07006028 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6029 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6030 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6031 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6032 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6033 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07006034 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006035 // Will throw a RuntimeException Resources.NotFoundException if this config value is
6036 // not found.
6037 return String.valueOf(getContext().getResources().getBoolean(
6038 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07006039 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07006040 return String.valueOf(getContext().getResources().getBoolean(
6041 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08006042 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6043 return String.valueOf(getContext().getResources().getBoolean(
6044 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07006045 } else {
6046 // null or unknown key
6047 return null;
6048 }
Glenn Kasten228c9842012-09-14 08:48:47 -07006049 }
6050
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006051 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08006052 * @hide
6053 * Sets an additional audio output device delay in milliseconds.
6054 *
6055 * The additional output delay is a request to the output device to
6056 * delay audio presentation (generally with respect to video presentation for better
6057 * synchronization).
6058 * It may not be supported by all output devices,
6059 * and typically increases the audio latency by the amount of additional
6060 * audio delay requested.
6061 *
6062 * If additional audio delay is supported by an audio output device,
6063 * it is expected to be supported for all output streams (and configurations)
6064 * opened on that device.
6065 *
6066 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07006067 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08006068 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6069 * @return true if successful, false if the device does not support output device delay
6070 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6071 */
6072 @SystemApi
6073 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
6074 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07006075 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006076 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006077 try {
6078 return getService().setAdditionalOutputDeviceDelay(
6079 new AudioDeviceAttributes(device), delayMillis);
6080 } catch (RemoteException e) {
6081 throw e.rethrowFromSystemServer();
6082 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006083 }
6084
6085 /**
6086 * @hide
6087 * Returns the current additional audio output device delay in milliseconds.
6088 *
6089 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6090 * @return the additional output device delay. This is a non-negative number.
6091 * {@code 0} is returned if unsupported.
6092 */
6093 @SystemApi
6094 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006095 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006096 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006097 try {
6098 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6099 } catch (RemoteException e) {
6100 throw e.rethrowFromSystemServer();
6101 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006102 }
6103
6104 /**
6105 * @hide
6106 * Returns the maximum additional audio output device delay in milliseconds.
6107 *
6108 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6109 * @return the maximum output device delay in milliseconds that can be set.
6110 * This is a non-negative number
6111 * representing the additional audio delay supported for the device.
6112 * {@code 0} is returned if unsupported.
6113 */
6114 @SystemApi
6115 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006116 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006117 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006118 try {
6119 return getService().getMaxAdditionalOutputDeviceDelay(
6120 new AudioDeviceAttributes(device));
6121 } catch (RemoteException e) {
6122 throw e.rethrowFromSystemServer();
6123 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006124 }
6125
6126 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006127 * Returns the estimated latency for the given stream type in milliseconds.
6128 *
6129 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6130 * a better solution.
6131 * @hide
6132 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006133 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006134 public int getOutputLatency(int streamType) {
6135 return AudioSystem.getOutputLatency(streamType);
6136 }
6137
John Spurlock3346a802014-05-20 16:25:37 -04006138 /**
6139 * Registers a global volume controller interface. Currently limited to SystemUI.
6140 *
6141 * @hide
6142 */
6143 public void setVolumeController(IVolumeController controller) {
6144 try {
6145 getService().setVolumeController(controller);
6146 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006147 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006148 }
6149 }
6150
6151 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006152 * Notify audio manager about volume controller visibility changes.
6153 * Currently limited to SystemUI.
6154 *
6155 * @hide
6156 */
6157 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6158 try {
6159 getService().notifyVolumeControllerVisible(controller, visible);
6160 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006161 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006162 }
6163 }
6164
6165 /**
John Spurlock3346a802014-05-20 16:25:37 -04006166 * Only useful for volume controllers.
6167 * @hide
6168 */
John Spurlock3346a802014-05-20 16:25:37 -04006169 public boolean isStreamAffectedByRingerMode(int streamType) {
6170 try {
6171 return getService().isStreamAffectedByRingerMode(streamType);
6172 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006173 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006174 }
6175 }
6176
6177 /**
6178 * Only useful for volume controllers.
6179 * @hide
6180 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006181 public boolean isStreamAffectedByMute(int streamType) {
6182 try {
6183 return getService().isStreamAffectedByMute(streamType);
6184 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006185 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006186 }
6187 }
6188
6189 /**
6190 * Only useful for volume controllers.
6191 * @hide
6192 */
John Spurlock3346a802014-05-20 16:25:37 -04006193 public void disableSafeMediaVolume() {
6194 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006195 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006196 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006197 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006198 }
6199 }
Eric Laurenta198a292014-02-18 16:26:17 -08006200
6201 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006202 * Only useful for volume controllers.
6203 * @hide
6204 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006205 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006206 public void setRingerModeInternal(int ringerMode) {
6207 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006208 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006209 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006210 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006211 }
6212 }
6213
6214 /**
6215 * Only useful for volume controllers.
6216 * @hide
6217 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006218 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006219 public int getRingerModeInternal() {
6220 try {
6221 return getService().getRingerModeInternal();
6222 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006223 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006224 }
6225 }
6226
6227 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006228 * Only useful for volume controllers.
6229 * @hide
6230 */
6231 public void setVolumePolicy(VolumePolicy policy) {
6232 try {
6233 getService().setVolumePolicy(policy);
6234 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006235 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006236 }
6237 }
6238
6239 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006240 * Set Hdmi Cec system audio mode.
6241 *
6242 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006243 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006244 * @hide
6245 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006246 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006247 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006248 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006249 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006250 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006251 }
6252 }
6253
6254 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006255 * Returns true if Hdmi Cec system audio mode is supported.
6256 *
6257 * @hide
6258 */
6259 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006260 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006261 public boolean isHdmiSystemAudioSupported() {
6262 try {
6263 return getService().isHdmiSystemAudioSupported();
6264 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006265 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006266 }
6267 }
6268
6269 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006270 * Return codes for listAudioPorts(), createAudioPatch() ...
6271 */
6272
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006273 /** @hide */
6274 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006275 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006276 /**
6277 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006278 */
6279 public static final int ERROR = AudioSystem.ERROR;
6280 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006281 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006282 */
6283 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6284 /** @hide
6285 */
6286 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6287 /** @hide
6288 */
6289 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6290 /** @hide
6291 */
6292 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006293 /**
6294 * An error code indicating that the object reporting it is no longer valid and needs to
6295 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006296 */
6297 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6298
6299 /**
6300 * Returns a list of descriptors for all audio ports managed by the audio framework.
6301 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6302 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6303 * See AudioPort for a list of attributes of each audio port.
6304 * @param ports An AudioPort ArrayList where the list will be returned.
6305 * @hide
6306 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006307 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006308 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006309 return updateAudioPortCache(ports, null, null);
6310 }
6311
6312 /**
6313 * Returns a list of descriptors for all audio ports managed by the audio framework as
6314 * it was before the last update calback.
6315 * @param ports An AudioPort ArrayList where the list will be returned.
6316 * @hide
6317 */
6318 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6319 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006320 }
6321
6322 /**
6323 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6324 * @see listAudioPorts(ArrayList<AudioPort>)
6325 * @hide
6326 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006327 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006328 if (devices == null) {
6329 return ERROR_BAD_VALUE;
6330 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006331 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006332 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006333 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006334 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006335 }
6336 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006337 }
6338
6339 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006340 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6341 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6342 * @hide
6343 */
6344 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6345 if (devices == null) {
6346 return ERROR_BAD_VALUE;
6347 }
6348 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6349 int status = updateAudioPortCache(null, null, ports);
6350 if (status == SUCCESS) {
6351 filterDevicePorts(ports, devices);
6352 }
6353 return status;
6354 }
6355
6356 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6357 ArrayList<AudioDevicePort> devices) {
6358 devices.clear();
6359 for (int i = 0; i < ports.size(); i++) {
6360 if (ports.get(i) instanceof AudioDevicePort) {
6361 devices.add((AudioDevicePort)ports.get(i));
6362 }
6363 }
6364 }
6365
6366 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006367 * Create a connection between two or more devices. The framework will reject the request if
6368 * device types are not compatible or the implementation does not support the requested
6369 * configuration.
6370 * NOTE: current implementation is limited to one source and one sink per patch.
6371 * @param patch AudioPatch array where the newly created patch will be returned.
6372 * As input, if patch[0] is not null, the specified patch will be replaced by the
6373 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6374 * patch and allows the implementation to optimize transitions.
6375 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6376 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6377 *
6378 * @return - {@link #SUCCESS} if connection is successful.
6379 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6380 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6381 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6382 * a patch.
6383 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6384 * - {@link #ERROR} if patch cannot be connected for any other reason.
6385 *
6386 * patch[0] contains the newly created patch
6387 * @hide
6388 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006389 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006390 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006391 AudioPortConfig[] sources,
6392 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006393 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006394 }
6395
6396 /**
6397 * Releases an existing audio patch connection.
6398 * @param patch The audio patch to disconnect.
6399 * @return - {@link #SUCCESS} if disconnection is successful.
6400 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6401 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6402 * a patch.
6403 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6404 * - {@link #ERROR} if patch cannot be released for any other reason.
6405 * @hide
6406 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006407 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006408 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006409 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006410 }
6411
6412 /**
6413 * List all existing connections between audio ports.
6414 * @param patches An AudioPatch array where the list will be returned.
6415 * @hide
6416 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006417 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006418 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006419 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006420 }
6421
6422 /**
6423 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6424 * AudioGain.buildConfig()
6425 * @hide
6426 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006427 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006428 if (port == null || gain == null) {
6429 return ERROR_BAD_VALUE;
6430 }
6431 AudioPortConfig activeConfig = port.activeConfig();
6432 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6433 activeConfig.channelMask(), activeConfig.format(), gain);
6434 config.mConfigMask = AudioPortConfig.GAIN;
6435 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006436 }
6437
6438 /**
6439 * Listener registered by client to be notified upon new audio port connections,
6440 * disconnections or attributes update.
6441 * @hide
6442 */
6443 public interface OnAudioPortUpdateListener {
6444 /**
6445 * Callback method called upon audio port list update.
6446 * @param portList the updated list of audio ports
6447 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006448 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006449
6450 /**
6451 * Callback method called upon audio patch list update.
6452 * @param patchList the updated list of audio patches
6453 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006454 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006455
6456 /**
6457 * Callback method called when the mediaserver dies
6458 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006459 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006460 }
6461
6462 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006463 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006464 * @hide
6465 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006466 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006467 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006468 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006469 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006470 }
6471
6472 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006473 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006474 * @hide
6475 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006476 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006477 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006478 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006479 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006480
6481 //
6482 // AudioPort implementation
6483 //
6484
Cole Faust7da659b2022-10-15 21:33:29 -07006485 private static final int AUDIOPORT_GENERATION_INIT = 0;
6486 private static Object sAudioPortGenerationLock = new Object();
6487 @GuardedBy("sAudioPortGenerationLock")
6488 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
6489 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
6490 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
6491 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006492
Eric Laurentf076db42015-01-14 13:23:27 -08006493 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006494 int generation;
Cole Faust7da659b2022-10-15 21:33:29 -07006495 synchronized (sAudioPortGenerationLock) {
Eric Laurentf076db42015-01-14 13:23:27 -08006496 generation = sAudioPortGeneration;
6497 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006498 }
6499 return generation;
6500 }
6501
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006502 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6503 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006504 sAudioPortEventHandler.init();
Cole Faust7da659b2022-10-15 21:33:29 -07006505 synchronized (sAudioPortGenerationLock) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006506
Eric Laurentf076db42015-01-14 13:23:27 -08006507 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006508 int[] patchGeneration = new int[1];
6509 int[] portGeneration = new int[1];
6510 int status;
6511 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6512 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6513
6514 do {
6515 newPorts.clear();
6516 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006517 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006518 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006519 return status;
6520 }
6521 newPatches.clear();
6522 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006523 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006524 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006525 return status;
6526 }
jiabinc4ecaa52017-09-26 14:28:41 -07006527 // Loop until patch generation is the same as port generation unless audio ports
6528 // and audio patches are not null.
6529 } while (patchGeneration[0] != portGeneration[0]
6530 && (ports == null || patches == null));
6531 // If the patch generation doesn't equal port generation, return ERROR here in case
6532 // of mismatch between audio ports and audio patches.
6533 if (patchGeneration[0] != portGeneration[0]) {
6534 return ERROR;
6535 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006536
6537 for (int i = 0; i < newPatches.size(); i++) {
6538 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006539 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6540 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006541 newPatches.get(i).sources()[j] = portCfg;
6542 }
6543 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006544 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6545 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006546 newPatches.get(i).sinks()[j] = portCfg;
6547 }
6548 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006549 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6550 AudioPatch newPatch = i.next();
6551 boolean hasInvalidPort = false;
6552 for (AudioPortConfig portCfg : newPatch.sources()) {
6553 if (portCfg == null) {
6554 hasInvalidPort = true;
6555 break;
6556 }
6557 }
6558 for (AudioPortConfig portCfg : newPatch.sinks()) {
6559 if (portCfg == null) {
6560 hasInvalidPort = true;
6561 break;
6562 }
6563 }
6564 if (hasInvalidPort) {
6565 // Temporarily remove patches with invalid ports. One who created the patch
6566 // is responsible for dealing with the port change.
6567 i.remove();
6568 }
6569 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006570
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006571 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006572 sAudioPortsCached = newPorts;
6573 sAudioPatchesCached = newPatches;
6574 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006575 }
6576 if (ports != null) {
6577 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006578 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006579 }
6580 if (patches != null) {
6581 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006582 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006583 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006584 if (previousPorts != null) {
6585 previousPorts.clear();
6586 previousPorts.addAll(sPreviousAudioPortsCached);
6587 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006588 }
6589 return SUCCESS;
6590 }
6591
Eric Laurentf076db42015-01-14 13:23:27 -08006592 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006593 AudioPort port = portCfg.port();
6594 int k;
6595 for (k = 0; k < ports.size(); k++) {
6596 // compare handles because the port returned by JNI is not of the correct
6597 // subclass
6598 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006599 port = ports.get(k);
6600 break;
6601 }
6602 }
6603 if (k == ports.size()) {
Darwin Huangbb111732022-10-21 13:14:32 +00006604 // This can happen in case of stale audio patch referring to a removed device and is
6605 // handled by the caller.
Eric Laurentb69681c2014-05-19 19:02:51 -07006606 return null;
6607 }
6608 AudioGainConfig gainCfg = portCfg.gain();
6609 if (gainCfg != null) {
6610 AudioGain gain = port.gain(gainCfg.index());
6611 gainCfg = gain.buildConfig(gainCfg.mode(),
6612 gainCfg.channelMask(),
6613 gainCfg.values(),
6614 gainCfg.rampDurationMs());
6615 }
6616 return port.buildConfig(portCfg.samplingRate(),
6617 portCfg.channelMask(),
6618 portCfg.format(),
6619 gainCfg);
6620 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006621
6622 private OnAmPortUpdateListener mPortListener = null;
6623
6624 /**
6625 * The message sent to apps when the contents of the device list changes if they provide
Andrew Solovay5c05ded2018-10-02 14:14:42 -07006626 * a {@link Handler} object to addOnAudioDeviceConnectionListener().
Paul McLeane3383cc2015-05-08 11:41:20 -07006627 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006628 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6629 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6630 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006631
Paul McLean8e6c9f42015-05-19 11:13:41 -07006632 /**
6633 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6634 */
Jack He89f97982018-05-02 19:10:56 -07006635 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006636 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006637
6638 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006639 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6640 * the results list to only those device types they are interested in.
6641 */
6642 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07006643 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6644 * source (i.e. input) audio devices.
6645 */
6646 public static final int GET_DEVICES_INPUTS = 0x0001;
6647
6648 /**
6649 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6650 * sink (i.e. output) audio devices.
6651 */
6652 public static final int GET_DEVICES_OUTPUTS = 0x0002;
6653
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006654 /** @hide */
6655 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6656 GET_DEVICES_INPUTS,
6657 GET_DEVICES_OUTPUTS }
6658 )
6659 @Retention(RetentionPolicy.SOURCE)
6660 public @interface AudioDeviceRole {}
6661
Paul McLeane3383cc2015-05-08 11:41:20 -07006662 /**
6663 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6664 * source and sink devices.
6665 */
6666 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6667
6668 /**
6669 * Determines if a given AudioDevicePort meets the specified filter criteria.
6670 * @param port The port to test.
6671 * @param flags A set of bitflags specifying the criteria to test.
6672 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6673 **/
6674 private static boolean checkFlags(AudioDevicePort port, int flags) {
6675 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6676 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6677 }
6678
Paul McLean11354572015-08-07 12:50:48 -06006679 private static boolean checkTypes(AudioDevicePort port) {
6680 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07006681 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06006682 }
6683
Paul McLeane3383cc2015-05-08 11:41:20 -07006684 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006685 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6686 * currently connected to the system and meeting the criteria specified in the
6687 * <code>flags</code> parameter.
Paul McLeane3383cc2015-05-08 11:41:20 -07006688 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006689 * @see #GET_DEVICES_OUTPUTS
6690 * @see #GET_DEVICES_INPUTS
6691 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07006692 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6693 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006694 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006695 return getDevicesStatic(flags);
6696 }
6697
Paul McLean8e6c9f42015-05-19 11:13:41 -07006698 /**
6699 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6700 * objects from the current (internal) AudioDevicePort list.
6701 */
Paul McLean03346882015-05-12 15:36:56 -07006702 private static AudioDeviceInfo[]
6703 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006704
Paul McLean8e6c9f42015-05-19 11:13:41 -07006705 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07006706 int numRecs = 0;
6707 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006708 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006709 numRecs++;
6710 }
6711 }
6712
Paul McLean8e6c9f42015-05-19 11:13:41 -07006713 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07006714 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6715 int slot = 0;
6716 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006717 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006718 deviceList[slot++] = new AudioDeviceInfo(port);
6719 }
6720 }
6721
6722 return deviceList;
6723 }
6724
Paul McLean03346882015-05-12 15:36:56 -07006725 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07006726 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6727 * the add/remove callback mechanism to provide a list of the newly added or removed devices
6728 * rather than the whole list and make the app figure it out.
6729 * Note that calling this method with:
6730 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6731 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07006732 */
6733 private static AudioDeviceInfo[] calcListDeltas(
6734 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6735
6736 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6737
6738 AudioDevicePort cur_port = null;
6739 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6740 boolean cur_port_found = false;
6741 cur_port = ports_B.get(cur_index);
6742 for (int prev_index = 0;
6743 prev_index < ports_A.size() && !cur_port_found;
6744 prev_index++) {
6745 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6746 }
6747
6748 if (!cur_port_found) {
6749 delta_ports.add(cur_port);
6750 }
6751 }
6752
6753 return infoListFromPortList(delta_ports, flags);
6754 }
6755
Paul McLeane3383cc2015-05-08 11:41:20 -07006756 /**
Paul McLean03346882015-05-12 15:36:56 -07006757 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6758 * connected to the system and meeting the criteria specified in the <code>flags</code>
6759 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006760 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07006761 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006762 * @see #GET_DEVICES_OUTPUTS
6763 * @see #GET_DEVICES_INPUTS
6764 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07006765 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6766 * @hide
6767 */
6768 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6769 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6770 int status = AudioManager.listAudioDevicePorts(ports);
6771 if (status != AudioManager.SUCCESS) {
6772 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07006773 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07006774 }
6775
6776 return infoListFromPortList(ports, flags);
6777 }
6778
6779 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07006780 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6781 * @param portId The audio port ID to look up for.
6782 * @param flags A set of bitflags specifying the criteria to test.
6783 * @see #GET_DEVICES_OUTPUTS
6784 * @see #GET_DEVICES_INPUTS
6785 * @see #GET_DEVICES_ALL
6786 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6787 * @hide
6788 */
6789 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6790 if (portId == 0) {
6791 return null;
6792 }
6793 AudioDeviceInfo[] devices = getDevicesStatic(flags);
6794 for (AudioDeviceInfo device : devices) {
6795 if (device.getId() == portId) {
6796 return device;
6797 }
6798 }
6799 return null;
6800 }
6801
6802 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006803 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07006804 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006805 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6806 * notifications.
6807 * @param handler Specifies the {@link Handler} object for the thread on which to execute
6808 * the callback. If <code>null</code>, the {@link Handler} associated with the main
6809 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07006810 */
Paul McLean03346882015-05-12 15:36:56 -07006811 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08006812 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07006813 synchronized (mDeviceCallbacks) {
6814 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006815 if (mDeviceCallbacks.size() == 0) {
6816 if (mPortListener == null) {
6817 mPortListener = new OnAmPortUpdateListener();
6818 }
6819 registerAudioPortUpdateListener(mPortListener);
6820 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006821 NativeEventHandlerDelegate delegate =
6822 new NativeEventHandlerDelegate(callback, handler);
6823 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07006824 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07006825 }
6826 }
6827 }
6828
6829 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006830 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07006831 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006832 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08006833 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07006834 */
Paul McLean03346882015-05-12 15:36:56 -07006835 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6836 synchronized (mDeviceCallbacks) {
6837 if (mDeviceCallbacks.containsKey(callback)) {
6838 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07006839 if (mDeviceCallbacks.size() == 0) {
6840 unregisterAudioPortUpdateListener(mPortListener);
6841 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006842 }
6843 }
6844 }
6845
jiabinc0f49442018-01-05 10:23:50 -08006846 /**
6847 * Set port id for microphones by matching device type and address.
6848 * @hide
6849 */
6850 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6851 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6852 for (int i = microphones.size() - 1; i >= 0; i--) {
6853 boolean foundPortId = false;
6854 for (AudioDeviceInfo device : devices) {
6855 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6856 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6857 microphones.get(i).setId(device.getId());
6858 foundPortId = true;
6859 break;
6860 }
6861 }
6862 if (!foundPortId) {
6863 Log.i(TAG, "Failed to find port id for device with type:"
6864 + microphones.get(i).getType() + " address:"
6865 + microphones.get(i).getAddress());
6866 microphones.remove(i);
6867 }
6868 }
6869 }
6870
6871 /**
jiabin589a2362018-02-22 16:21:53 -08006872 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6873 * @hide
6874 */
6875 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6876 int deviceType = deviceInfo.getType();
6877 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6878 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6879 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6880 : MicrophoneInfo.LOCATION_PERIPHERAL;
6881 MicrophoneInfo microphone = new MicrophoneInfo(
6882 deviceInfo.getPort().name() + deviceInfo.getId(),
6883 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6884 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6885 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6886 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6887 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6888 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6889 microphone.setId(deviceInfo.getId());
6890 return microphone;
6891 }
6892
6893 /**
jiabind0be5b22018-04-10 14:10:04 -07006894 * Add {@link MicrophoneInfo} by device information while filtering certain types.
6895 */
6896 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6897 HashSet<Integer> filterTypes) {
6898 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6899 for (AudioDeviceInfo device : devices) {
6900 if (filterTypes.contains(device.getType())) {
6901 continue;
6902 }
6903 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6904 microphones.add(microphone);
6905 }
6906 }
6907
6908 /**
jiabinc0f49442018-01-05 10:23:50 -08006909 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6910 * of all available microphones. The list is empty when no microphones are available
6911 * on the device. An error during the query will result in an IOException being thrown.
6912 *
6913 * @return a list that contains all microphones' characteristics
6914 * @throws IOException if an error occurs.
6915 */
6916 public List<MicrophoneInfo> getMicrophones() throws IOException {
6917 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6918 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006919 HashSet<Integer> filterTypes = new HashSet<>();
6920 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08006921 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07006922 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07006923 if (status != AudioManager.ERROR_INVALID_OPERATION) {
6924 Log.e(TAG, "getMicrophones failed:" + status);
6925 }
6926 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07006927 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6928 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08006929 }
6930 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006931 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6932 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08006933 return microphones;
6934 }
6935
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006936 /**
6937 * Returns a list of audio formats that corresponds to encoding formats
William Escandea05cb452021-12-08 14:14:19 +01006938 * supported on offload path for A2DP playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006939 *
6940 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
William Escandea05cb452021-12-08 14:14:19 +01006941 * supported for offload A2DP playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006942 * @hide
6943 */
William Escandea05cb452021-12-08 14:14:19 +01006944 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6945 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
6946 ArrayList<Integer> formatsList = new ArrayList<>();
6947 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006948
William Escandea05cb452021-12-08 14:14:19 +01006949 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
6950 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006951 if (status != AudioManager.SUCCESS) {
William Escandea05cb452021-12-08 14:14:19 +01006952 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
6953 return codecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006954 }
6955
William Escandea05cb452021-12-08 14:14:19 +01006956 for (Integer format : formatsList) {
6957 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6958 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
Etienne Ruffieux2c5180a2022-03-08 13:31:41 +00006959 codecConfigList.add(
6960 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006961 }
William Escandea05cb452021-12-08 14:14:19 +01006962 }
6963 return codecConfigList;
6964 }
6965
6966 /**
6967 * Returns a list of audio formats that corresponds to encoding formats
6968 * supported on offload path for Le audio playback.
6969 *
6970 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
6971 * supported for offload Le Audio playback
6972 * @hide
6973 */
6974 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6975 @NonNull
6976 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
6977 ArrayList<Integer> formatsList = new ArrayList<>();
6978 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
6979
6980 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
6981 AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
6982 if (status != AudioManager.SUCCESS) {
6983 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
Patty46694212021-11-04 21:03:32 +08006984 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006985 }
William Escandea05cb452021-12-08 14:14:19 +01006986
6987 for (Integer format : formatsList) {
6988 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
6989 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6990 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
6991 .setCodecType(btLeAudioCodec)
6992 .build());
6993 }
6994 }
6995 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006996 }
6997
Paul McLeancbeb8a22015-06-10 08:21:27 -07006998 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
6999 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
7000 // of the ports that exist at the time of the last notification.
7001 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
7002
Paul McLeane3383cc2015-05-08 11:41:20 -07007003 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07007004 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07007005 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07007006 */
jiabin8c3a7672018-05-22 15:44:21 -07007007 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07007008 int status;
7009
Paul McLeancbeb8a22015-06-10 08:21:27 -07007010 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07007011 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
7012 status = AudioManager.listAudioDevicePorts(current_ports);
7013 if (status != AudioManager.SUCCESS) {
7014 return;
7015 }
7016
Paul McLeancbeb8a22015-06-10 08:21:27 -07007017 if (handler != null) {
7018 // This is the callback for the registration, so send the current list
7019 AudioDeviceInfo[] deviceList =
7020 infoListFromPortList(current_ports, GET_DEVICES_ALL);
7021 handler.sendMessage(
7022 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
7023 } else {
7024 AudioDeviceInfo[] added_devices =
7025 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
7026 AudioDeviceInfo[] removed_devices =
7027 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07007028 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07007029 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
7030 handler = mDeviceCallbacks.valueAt(i).getHandler();
7031 if (handler != null) {
7032 if (removed_devices.length != 0) {
7033 handler.sendMessage(Message.obtain(handler,
7034 MSG_DEVICES_DEVICES_REMOVED,
7035 removed_devices));
7036 }
7037 if (added_devices.length != 0) {
7038 handler.sendMessage(Message.obtain(handler,
7039 MSG_DEVICES_DEVICES_ADDED,
7040 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07007041 }
Paul McLean03346882015-05-12 15:36:56 -07007042 }
7043 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007044 }
7045 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07007046
7047 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07007048 }
7049
7050 /**
7051 * Handles Port list update notifications from the AudioManager
7052 */
7053 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
7054 static final String TAG = "OnAmPortUpdateListener";
7055 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07007056 synchronized (mDeviceCallbacks) {
7057 broadcastDeviceListChange_sync(null);
7058 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007059 }
7060
7061 /**
7062 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07007063 * Note: We don't do anything with Patches at this time, so ignore this notification.
7064 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07007065 */
7066 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
7067
7068 /**
7069 * Callback method called when the mediaserver dies
7070 */
7071 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07007072 synchronized (mDeviceCallbacks) {
7073 broadcastDeviceListChange_sync(null);
7074 }
Paul McLeane3383cc2015-05-08 11:41:20 -07007075 }
7076 }
7077
Eric Laurent1d3cdce2018-01-20 10:31:21 -08007078
7079 /**
7080 * @hide
7081 * Abstract class to receive event notification about audioserver process state.
7082 */
7083 @SystemApi
7084 public abstract static class AudioServerStateCallback {
7085 public void onAudioServerDown() { }
7086 public void onAudioServerUp() { }
7087 }
7088
7089 private Executor mAudioServerStateExec;
7090 private AudioServerStateCallback mAudioServerStateCb;
7091 private final Object mAudioServerStateCbLock = new Object();
7092
7093 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
7094 new IAudioServerStateDispatcher.Stub() {
7095 @Override
7096 public void dispatchAudioServerStateChange(boolean state) {
7097 Executor exec;
7098 AudioServerStateCallback cb;
7099
7100 synchronized (mAudioServerStateCbLock) {
7101 exec = mAudioServerStateExec;
7102 cb = mAudioServerStateCb;
7103 }
7104
7105 if ((exec == null) || (cb == null)) {
7106 return;
7107 }
7108 if (state) {
7109 exec.execute(() -> cb.onAudioServerUp());
7110 } else {
7111 exec.execute(() -> cb.onAudioServerDown());
7112 }
7113 }
7114 };
7115
7116 /**
7117 * @hide
7118 * Registers a callback for notification of audio server state changes.
7119 * @param executor {@link Executor} to handle the callbacks
7120 * @param stateCallback the callback to receive the audio server state changes
7121 * To remove the callabck, pass a null reference for both executor and stateCallback.
7122 */
7123 @SystemApi
7124 public void setAudioServerStateCallback(@NonNull Executor executor,
7125 @NonNull AudioServerStateCallback stateCallback) {
7126 if (stateCallback == null) {
7127 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
7128 }
7129 if (executor == null) {
7130 throw new IllegalArgumentException(
7131 "Illegal null Executor for the AudioServerStateCallback");
7132 }
7133
7134 synchronized (mAudioServerStateCbLock) {
7135 if (mAudioServerStateCb != null) {
7136 throw new IllegalStateException(
7137 "setAudioServerStateCallback called with already registered callabck");
7138 }
7139 final IAudioService service = getService();
7140 try {
7141 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7142 } catch (RemoteException e) {
7143 throw e.rethrowFromSystemServer();
7144 }
7145 mAudioServerStateExec = executor;
7146 mAudioServerStateCb = stateCallback;
7147 }
7148 }
7149
7150 /**
7151 * @hide
7152 * Unregisters the callback for notification of audio server state changes.
7153 */
7154 @SystemApi
7155 public void clearAudioServerStateCallback() {
7156 synchronized (mAudioServerStateCbLock) {
7157 if (mAudioServerStateCb != null) {
7158 final IAudioService service = getService();
7159 try {
7160 service.unregisterAudioServerStateDispatcher(
7161 mAudioServerStateDispatcher);
7162 } catch (RemoteException e) {
7163 throw e.rethrowFromSystemServer();
7164 }
7165 }
7166 mAudioServerStateExec = null;
7167 mAudioServerStateCb = null;
7168 }
7169 }
7170
7171 /**
7172 * @hide
7173 * Checks if native audioservice is running or not.
7174 * @return true if native audioservice runs, false otherwise.
7175 */
7176 @SystemApi
7177 public boolean isAudioServerRunning() {
7178 final IAudioService service = getService();
7179 try {
7180 return service.isAudioServerRunning();
7181 } catch (RemoteException e) {
7182 throw e.rethrowFromSystemServer();
7183 }
7184 }
7185
jiabin39940752018-04-02 18:18:45 -07007186 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007187 * Sets the surround sound mode.
7188 *
7189 * @return true if successful, otherwise false
7190 */
7191 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
7192 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7193 try {
7194 return getService().setEncodedSurroundMode(mode);
7195 } catch (RemoteException e) {
7196 throw e.rethrowFromSystemServer();
7197 }
7198 }
7199
7200 /**
7201 * Gets the surround sound mode.
7202 *
7203 * @return true if successful, otherwise false
7204 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007205 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7206 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007207 return getService().getEncodedSurroundMode(
7208 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007209 } catch (RemoteException e) {
7210 throw e.rethrowFromSystemServer();
7211 }
7212 }
7213
7214 /**
jiabin39940752018-04-02 18:18:45 -07007215 * @hide
7216 * Returns all surround formats.
7217 * @return a map where the key is a surround format and
7218 * the value indicates the surround format is enabled or not
7219 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007220 @TestApi
7221 @NonNull
jiabin39940752018-04-02 18:18:45 -07007222 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007223 try {
7224 return getService().getSurroundFormats();
7225 } catch (RemoteException e) {
7226 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007227 }
jiabin39940752018-04-02 18:18:45 -07007228 }
7229
7230 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007231 * Sets and persists a certain surround format as enabled or not.
7232 * <p>
7233 * This API is called by TvSettings surround sound menu when user enables or disables a
7234 * surround sound format. This setting is persisted as global user setting.
7235 * Applications should revert their changes to surround sound settings unless they intend to
7236 * modify the global user settings across all apps. The framework does not auto-revert an
7237 * application's settings after a lifecycle event. Audio focus is not required to apply these
7238 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007239 *
jiabin39940752018-04-02 18:18:45 -07007240 * @param enabled the required surround format state, true for enabled, false for disabled
7241 * @return true if successful, otherwise false
7242 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007243 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007244 public boolean setSurroundFormatEnabled(
7245 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007246 try {
7247 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7248 } catch (RemoteException e) {
7249 throw e.rethrowFromSystemServer();
7250 }
7251 }
7252
7253 /**
7254 * Gets whether a certain surround format is enabled or not.
7255 * @param audioFormat a surround format
7256 *
7257 * @return whether the required surround format is enabled
7258 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007259 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7260 try {
7261 return getService().isSurroundFormatEnabled(audioFormat);
7262 } catch (RemoteException e) {
7263 throw e.rethrowFromSystemServer();
7264 }
jiabin39940752018-04-02 18:18:45 -07007265 }
7266
7267 /**
7268 * @hide
7269 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007270 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007271 *
Kriti Dang01924232021-03-02 13:51:09 +01007272 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007273 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007274 @TestApi
7275 @NonNull
7276 public List<Integer> getReportedSurroundFormats() {
7277 try {
7278 return getService().getReportedSurroundFormats();
7279 } catch (RemoteException e) {
7280 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007281 }
jiabin39940752018-04-02 18:18:45 -07007282 }
7283
jiabin66f9e722018-11-02 16:20:19 -07007284 /**
7285 * Return if audio haptic coupled playback is supported or not.
7286 *
7287 * @return whether audio haptic playback supported.
7288 */
7289 public static boolean isHapticPlaybackSupported() {
7290 return AudioSystem.isHapticPlaybackSupported();
7291 }
7292
François Gaffie0699fec2018-07-09 14:35:10 +02007293 /**
7294 * @hide
Carter Hsu2065d1e2022-01-19 19:54:50 +08007295 * Indicates whether a platform supports the Ultrasound feature which covers the playback
7296 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
7297 * usage will be
7298 * To start the Ultrasound playback:
7299 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
7300 * To start the Ultrasound capture:
7301 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
7302 *
7303 * @return whether the ultrasound feature is supported, true when platform supports both
7304 * Ultrasound playback and capture, false otherwise.
7305 */
7306 @SystemApi
Carter Hsu3ea30de42022-02-15 15:59:00 +08007307 @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
7308 public boolean isUltrasoundSupported() {
7309 try {
7310 return getService().isUltrasoundSupported();
7311 } catch (RemoteException e) {
7312 throw e.rethrowFromSystemServer();
7313 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08007314 }
7315
7316 /**
7317 * @hide
François Gaffie0699fec2018-07-09 14:35:10 +02007318 * Introspection API to retrieve audio product strategies.
7319 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7320 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7321 * by OEM without any needs of AOSP patches.
7322 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7323 * strategy refered either by its index or human readable string. It will allow clients
7324 * application to start streaming data using these {@link AudioAttributes} on the selected
7325 * device by Audio Policy Engine.
7326 * @return a (possibly zero-length) array of
7327 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7328 */
7329 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007330 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007331 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007332 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007333 final IAudioService service = getService();
7334 try {
7335 return service.getAudioProductStrategies();
7336 } catch (RemoteException e) {
7337 throw e.rethrowFromSystemServer();
7338 }
7339 }
7340
François Gaffieadcd00a2018-09-18 17:06:26 +02007341 /**
7342 * @hide
7343 * Introspection API to retrieve audio volume groups.
7344 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7345 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007346 * @return a (possibly zero-length) List of
7347 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007348 */
7349 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007350 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007351 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007352 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007353 final IAudioService service = getService();
7354 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007355 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007356 } catch (RemoteException e) {
7357 throw e.rethrowFromSystemServer();
7358 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007359 }
7360
7361 /**
7362 * @hide
7363 * Callback registered by client to be notified upon volume group change.
7364 */
7365 @SystemApi
7366 public abstract static class VolumeGroupCallback {
7367 /**
7368 * Callback method called upon audio volume group change.
7369 * @param group the group for which the volume has changed
7370 */
7371 public void onAudioVolumeGroupChanged(int group, int flags) {}
7372 }
7373
7374 /**
7375 * @hide
7376 * Register an audio volume group change listener.
7377 * @param callback the {@link VolumeGroupCallback} to register
7378 */
7379 @SystemApi
7380 public void registerVolumeGroupCallback(
7381 @NonNull Executor executor,
7382 @NonNull VolumeGroupCallback callback) {
7383 Preconditions.checkNotNull(executor, "executor must not be null");
7384 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7385 sAudioAudioVolumeGroupChangedHandler.init();
7386 // TODO: make use of executor
7387 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7388 }
7389
7390 /**
7391 * @hide
7392 * Unregister an audio volume group change listener.
7393 * @param callback the {@link VolumeGroupCallback} to unregister
7394 */
7395 @SystemApi
7396 public void unregisterVolumeGroupCallback(
7397 @NonNull VolumeGroupCallback callback) {
7398 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7399 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7400 }
jiabin39940752018-04-02 18:18:45 -07007401
jiabinad225202019-03-20 15:22:50 -07007402 /**
7403 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007404 *
7405 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007406 * @param uri the {@link Uri} of the asset.
7407 * @return true if the assert contains haptic channels.
7408 * @hide
7409 */
jiabincfcf1032021-07-01 16:30:50 -07007410 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7411 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007412 try {
jiabincfcf1032021-07-01 16:30:50 -07007413 extractor.setDataSource(context, uri, null);
7414 for (int i = 0; i < extractor.getTrackCount(); i++) {
7415 MediaFormat format = extractor.getTrackFormat(i);
7416 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7417 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7418 return true;
7419 }
7420 }
7421 } catch (IOException e) {
7422 Log.e(TAG, "hasHapticChannels failure:" + e);
7423 }
7424 return false;
7425 }
7426
7427 /**
7428 * Return if an asset contains haptic channels or not.
7429 *
7430 * @param context the {@link Context} to resolve the uri.
7431 * @param uri the {@link Uri} of the asset.
7432 * @return true if the assert contains haptic channels.
7433 * @hide
7434 */
7435 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7436 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07007437
jiabincfcf1032021-07-01 16:30:50 -07007438 if (context != null) {
7439 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07007440 }
7441
7442 Context cachedContext = sContext.get();
7443 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07007444 if (DEBUG) {
7445 Log.d(TAG, "Try to use static context to query if having haptic channels");
7446 }
jiabin0f3339c2021-07-09 11:50:07 -07007447 return hasHapticChannelsImpl(cachedContext, uri);
7448 }
7449
7450 // Try with audio service context, this may fail to get correct result.
7451 if (DEBUG) {
7452 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7453 }
7454 try {
7455 return getService().hasHapticChannels(uri);
7456 } catch (RemoteException e) {
7457 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07007458 }
7459 }
7460
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007461 /**
7462 * Set whether or not there is an active RTT call.
7463 * This method should be called by Telecom service.
7464 * @hide
7465 * TODO: make this a @SystemApi
7466 */
7467 public static void setRttEnabled(boolean rttEnabled) {
7468 try {
7469 getService().setRttEnabled(rttEnabled);
7470 } catch (RemoteException e) {
7471 throw e.rethrowFromSystemServer();
7472 }
7473 }
7474
Jin Seok Park16aeba382020-08-06 12:52:54 +09007475 /**
7476 * Adjusts the volume of the most relevant stream, or the given fallback
7477 * stream.
7478 * <p>
7479 * This method should only be used by applications that replace the
7480 * platform-wide management of audio settings or the main telephony
7481 * application.
7482 * <p>
7483 * This method has no effect if the device implements a fixed volume policy
7484 * as indicated by {@link #isVolumeFixed()}.
7485 * <p>This API checks if the caller has the necessary permissions based on the provided
7486 * component name, uid, and pid values.
7487 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7488 *
7489 * @param suggestedStreamType The stream type that will be used if there
7490 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7491 * valid here.
7492 * @param direction The direction to adjust the volume. One of
7493 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7494 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7495 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7496 * @param flags One or more flags.
7497 * @param packageName the package name of client application
7498 * @param uid the uid of client application
7499 * @param pid the pid of client application
7500 * @param targetSdkVersion the target sdk version of client application
7501 * @see #adjustVolume(int, int)
7502 * @see #adjustStreamVolume(int, int, int)
7503 * @see #setStreamVolume(int, int, int)
7504 * @see #isVolumeFixed()
7505 *
7506 * @hide
7507 */
7508 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7509 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7510 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7511 try {
7512 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7513 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7514 } catch (RemoteException e) {
7515 throw e.rethrowFromSystemServer();
7516 }
7517 }
7518
7519 /**
7520 * Adjusts the volume of a particular stream by one step in a direction.
7521 * <p>
7522 * This method should only be used by applications that replace the platform-wide
7523 * management of audio settings or the main telephony application.
7524 * <p>This method has no effect if the device implements a fixed volume policy
7525 * as indicated by {@link #isVolumeFixed()}.
7526 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7527 * unless the app has been granted Do Not Disturb Access.
7528 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7529 * <p>This API checks if the caller has the necessary permissions based on the provided
7530 * component name, uid, and pid values.
7531 * See {@link #adjustStreamVolume(int, int, int)}.
7532 *
7533 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7534 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7535 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7536 * @param direction The direction to adjust the volume. One of
7537 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7538 * {@link #ADJUST_SAME}.
7539 * @param flags One or more flags.
7540 * @param packageName the package name of client application
7541 * @param uid the uid of client application
7542 * @param pid the pid of client application
7543 * @param targetSdkVersion the target sdk version of client application
7544 * @see #adjustVolume(int, int)
7545 * @see #setStreamVolume(int, int, int)
7546 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7547 * and the caller is not granted notification policy access.
7548 *
7549 * @hide
7550 */
7551 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7552 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7553 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7554 try {
7555 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7556 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7557 } catch (RemoteException e) {
7558 throw e.rethrowFromSystemServer();
7559 }
7560 }
7561
7562 /**
7563 * Sets the volume index for a particular stream.
7564 * <p>This method has no effect if the device implements a fixed volume policy
7565 * as indicated by {@link #isVolumeFixed()}.
7566 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7567 * the app has been granted Do Not Disturb Access.
7568 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7569 * <p>This API checks if the caller has the necessary permissions based on the provided
7570 * component name, uid, and pid values.
7571 * See {@link #setStreamVolume(int, int, int)}.
7572 *
7573 * @param streamType The stream whose volume index should be set.
7574 * @param index The volume index to set. See
7575 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7576 * @param flags One or more flags.
7577 * @param packageName the package name of client application
7578 * @param uid the uid of client application
7579 * @param pid the pid of client application
7580 * @param targetSdkVersion the target sdk version of client application
7581 * @see #getStreamMaxVolume(int)
7582 * @see #getStreamVolume(int)
7583 * @see #isVolumeFixed()
7584 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7585 * and the caller is not granted notification policy access.
7586 *
7587 * @hide
7588 */
7589 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7590 public void setStreamVolumeForUid(int streamType, int index, int flags,
7591 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7592 try {
7593 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7594 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7595 } catch (RemoteException e) {
7596 throw e.rethrowFromSystemServer();
7597 }
7598 }
7599
7600
hjin81.lee4e984e52019-12-05 14:34:52 +09007601 /** @hide
7602 * TODO: make this a @SystemApi */
7603 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7604 public void setMultiAudioFocusEnabled(boolean enabled) {
7605 try {
7606 getService().setMultiAudioFocusEnabled(enabled);
7607 } catch (RemoteException e) {
7608 throw e.rethrowFromSystemServer();
7609 }
7610 }
7611
Eric Laurent43a78de2020-07-24 17:11:15 -07007612
7613 /**
7614 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7615 * For more details on Hardware A/V synchronization please refer to
7616 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7617 * media tunneling documentation</a>.
7618 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7619 * @return the HW A/V sync ID for this audio session (an integer different from 0).
7620 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7621 */
7622 public int getAudioHwSyncForSession(int sessionId) {
7623 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7624 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7625 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7626 }
7627 return hwSyncId;
7628 }
7629
Eric Laurentb36d4a12020-10-09 09:52:49 -07007630 /**
7631 * Selects the audio device that should be used for communication use cases, for instance voice
7632 * or video calls. This method can be used by voice or video chat applications to select a
7633 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01007634 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7635 * {@link #getAvailableCommunicationDevices()}.
7636 * The selection is active as long as the requesting application process lives, until
7637 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007638 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01007639 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007640 * <p>In case of simultaneous requests by multiple applications the priority is given to the
7641 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7642 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7643 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7644 * telephony application with permission
7645 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7646 * <p> If the requested devices is not currently available, the request will be rejected and
7647 * the method will return false.
7648 * <p>This API replaces the following deprecated APIs:
7649 * <ul>
7650 * <li> {@link #startBluetoothSco()}
7651 * <li> {@link #stopBluetoothSco()}
7652 * <li> {@link #setSpeakerphoneOn(boolean)}
7653 * </ul>
7654 * <h4>Example</h4>
7655 * <p>The example below shows how to enable and disable speakerphone mode.
7656 * <pre class="prettyprint">
7657 * // Get an AudioManager instance
7658 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01007659 * AudioDeviceInfo speakerDevice = null;
7660 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7661 * for (AudioDeviceInfo device : devices) {
7662 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7663 * speakerDevice = device;
7664 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007665 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007666 * }
7667 * if (speakerDevice != null) {
7668 * // Turn speakerphone ON.
7669 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
7670 * if (!result) {
7671 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007672 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007673 * // Turn speakerphone OFF.
7674 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007675 * }
7676 * </pre>
7677 * @param device the requested audio device.
7678 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7679 * @throws IllegalArgumentException If an invalid device is specified.
7680 */
Eric Laurent7412f572021-02-11 15:10:31 +01007681 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007682 Objects.requireNonNull(device);
7683 try {
7684 if (device.getId() == 0) {
7685 throw new IllegalArgumentException("In valid device: " + device);
7686 }
Eric Laurent7412f572021-02-11 15:10:31 +01007687 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007688 } catch (RemoteException e) {
7689 throw e.rethrowFromSystemServer();
7690 }
7691 }
7692
7693 /**
7694 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01007695 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007696 */
Eric Laurent7412f572021-02-11 15:10:31 +01007697 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007698 try {
Eric Laurent7412f572021-02-11 15:10:31 +01007699 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007700 } catch (RemoteException e) {
7701 throw e.rethrowFromSystemServer();
7702 }
7703 }
7704
7705 /**
7706 * Returns currently selected audio device for communication.
7707 * <p>This API replaces the following deprecated APIs:
7708 * <ul>
7709 * <li> {@link #isBluetoothScoOn()}
7710 * <li> {@link #isSpeakerphoneOn()}
7711 * </ul>
7712 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01007713 * currently selected for communication use cases. Can be null on platforms
7714 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007715 * is used.
7716 */
7717 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01007718 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007719 try {
7720 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01007721 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7722 } catch (RemoteException e) {
7723 throw e.rethrowFromSystemServer();
7724 }
7725 }
7726
7727 /**
7728 * Returns a list of audio devices that can be selected for communication use cases via
7729 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7730 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7731 */
7732 @NonNull
7733 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7734 try {
7735 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7736 int[] portIds = getService().getAvailableCommunicationDeviceIds();
7737 for (int portId : portIds) {
7738 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7739 if (device == null) {
7740 continue;
7741 }
7742 devices.add(device);
7743 }
7744 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007745 } catch (RemoteException e) {
7746 throw e.rethrowFromSystemServer();
7747 }
7748 }
7749
7750 /**
Dorin Drimuseb9bf642022-01-03 12:05:37 +01007751 * Returns a list of direct {@link AudioProfile} that are supported for the specified
7752 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
7753 * is possible.
7754 *
7755 * <p>Direct playback means that the audio stream is not resampled or downmixed
7756 * by the framework. Checking for direct support can help the app select the representation
7757 * of audio content that most closely matches the capabilities of the device and peripherals
7758 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
7759 * or mixed with other streams, if needed.
7760 * <p>When using this information to inform your application which audio format to play,
7761 * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
7762 * @param attributes a non-null {@link AudioAttributes} instance.
7763 * @return a list of {@link AudioProfile}
7764 */
7765 @NonNull
7766 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
7767 Objects.requireNonNull(attributes);
7768 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
7769 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
7770 if (status != SUCCESS) {
7771 Log.w(TAG, "getDirectProfilesForAttributes failed.");
7772 return new ArrayList<>();
7773 }
7774 return audioProfilesList;
7775 }
7776
7777 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007778 * @hide
7779 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7780 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7781 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7782 * The method will return null if no device of the provided type is connected.
7783 * If more than one device of the provided type is connected, an object corresponding to the
7784 * first device encountered in the enumeration list will be returned.
7785 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01007786 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007787 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7788 * @throws IllegalArgumentException If an invalid device type is specified.
7789 */
7790 @TestApi
7791 @Nullable
7792 public static AudioDeviceInfo getDeviceInfoFromType(
7793 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01007794 return getDeviceInfoFromTypeAndAddress(deviceType, null);
7795 }
7796
Eric Laurent78eef3a2021-11-09 16:10:42 +01007797 /**
Eric Laurent7412f572021-02-11 15:10:31 +01007798 * @hide
7799 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7800 * address provided.
7801 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7802 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7803 * If a null address is provided, the matching will happen on the type only.
7804 * The method will return null if no device of the provided type and address is connected.
7805 * If more than one device of the provided type is connected, an object corresponding to the
7806 * first device encountered in the enumeration list will be returned.
7807 * @param type The device device for which an <code>AudioDeviceInfo</code>
7808 * object is queried.
7809 * @param address The device address for which an <code>AudioDeviceInfo</code>
7810 * object is queried or null if requesting match on type only.
7811 * @return An AudioDeviceInfo object or null if no matching device is connected.
7812 * @throws IllegalArgumentException If an invalid device type is specified.
7813 */
7814 @Nullable
7815 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7816 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007817 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01007818 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007819 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01007820 if (device.getType() == type) {
7821 deviceForType = device;
7822 if (address == null || address.equals(device.getAddress())) {
7823 return device;
7824 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007825 }
7826 }
Eric Laurent7412f572021-02-11 15:10:31 +01007827 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007828 }
7829
7830 /**
7831 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007832 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007833 */
7834 public interface OnCommunicationDeviceChangedListener {
7835 /**
7836 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007837 * @param device the audio device requested for communication use cases.
7838 * Can be null on platforms not supporting
7839 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007840 */
7841 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7842 }
7843
7844 /**
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007845 * manages the OnCommunicationDeviceChangedListener listeners and the
7846 * CommunicationDeviceDispatcherStub
7847 */
7848 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
7849 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
7850 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07007851 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007852 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007853 * @param executor
7854 * @param listener
7855 */
7856 public void addOnCommunicationDeviceChangedListener(
7857 @NonNull @CallbackExecutor Executor executor,
7858 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007859 mCommDeviceChangedListenerMgr.addListener(
7860 executor, listener, "addOnCommunicationDeviceChangedListener",
7861 () -> new CommunicationDeviceDispatcherStub());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007862 }
7863
7864 /**
7865 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007866 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007867 * @param listener
7868 */
7869 public void removeOnCommunicationDeviceChangedListener(
7870 @NonNull OnCommunicationDeviceChangedListener listener) {
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007871 mCommDeviceChangedListenerMgr.removeListener(listener,
7872 "removeOnCommunicationDeviceChangedListener");
Eric Laurentb36d4a12020-10-09 09:52:49 -07007873 }
7874
Eric Laurentb36d4a12020-10-09 09:52:49 -07007875 private final class CommunicationDeviceDispatcherStub
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007876 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007877
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007878 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007879 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007880 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007881 if (register) {
7882 getService().registerCommunicationDeviceDispatcher(this);
7883 } else {
7884 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007885 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007886 } catch (RemoteException e) {
7887 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007888 }
7889 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007890
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007891 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007892 public void dispatchCommunicationDeviceChanged(int portId) {
7893 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
Jean-Michel Trivi54d129f2021-12-30 17:43:47 -08007894 mCommDeviceChangedListenerMgr.callListeners(
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007895 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07007896 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007897 }
7898
Eric Laurent78eef3a2021-11-09 16:10:42 +01007899
7900 /**
7901 * @hide
7902 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
7903 * PSTN call.
7904 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
7905 * an AudioTrack for call uplink audio injection and
7906 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
7907 * an AudioRecord for call downlink audio extraction.
7908 * @return true if PSTN call audio is accessible, false otherwise.
7909 */
7910 @TestApi
7911 @SystemApi
7912 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
7913 public boolean isPstnCallAudioInterceptable() {
7914 final IAudioService service = getService();
7915 try {
7916 return service.isPstnCallAudioInterceptable();
7917 } catch (RemoteException e) {
7918 throw e.rethrowFromSystemServer();
7919 }
7920 }
7921
7922 /** @hide */
7923 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
7924 CALL_REDIRECT_NONE,
7925 CALL_REDIRECT_PSTN,
7926 CALL_REDIRECT_VOIP }
7927 )
7928 @Retention(RetentionPolicy.SOURCE)
7929 public @interface CallRedirectionMode {}
7930
7931 /**
7932 * Not used for call redirection
7933 * @hide
7934 */
7935 public static final int CALL_REDIRECT_NONE = 0;
7936 /**
7937 * Used to redirect PSTN call
7938 * @hide
7939 */
7940 public static final int CALL_REDIRECT_PSTN = 1;
7941 /**
7942 * Used to redirect VoIP call
7943 * @hide
7944 */
7945 public static final int CALL_REDIRECT_VOIP = 2;
7946
7947
7948 private @CallRedirectionMode int getCallRedirectMode() {
7949 int mode = getMode();
7950 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
7951 || mode == MODE_CALL_REDIRECT) {
7952 return CALL_REDIRECT_PSTN;
7953 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
7954 return CALL_REDIRECT_VOIP;
7955 }
7956 return CALL_REDIRECT_NONE;
7957 }
7958
7959 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
7960 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
7961 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
7962 throw new UnsupportedOperationException(" Unsupported encoding ");
7963 }
7964 if (format.getSampleRate() < 8000
7965 || format.getSampleRate() > 48000) {
7966 throw new UnsupportedOperationException(" Unsupported sample rate ");
7967 }
7968 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
7969 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
7970 throw new UnsupportedOperationException(" Unsupported output channel mask ");
7971 }
7972 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
7973 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
7974 throw new UnsupportedOperationException(" Unsupported input channel mask ");
7975 }
7976 }
7977
7978 class CallIRedirectionClientInfo {
7979 public WeakReference trackOrRecord;
7980 public int redirectMode;
7981 }
7982
7983 private Object mCallRedirectionLock = new Object();
7984 @GuardedBy("mCallRedirectionLock")
7985 private CallInjectionModeChangedListener mCallRedirectionModeListener;
7986 @GuardedBy("mCallRedirectionLock")
7987 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
7988
7989 /**
7990 * @hide
7991 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
7992 * This can be used for functions like call screening or call audio redirection and is reserved
7993 * to system apps with privileged permission.
7994 * @param format the desired audio format for audio playback.
7995 * p>Formats accepted are:
7996 * <ul>
7997 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
7998 * <li><em>Channel mask</em> - Mono or Stereo </li>
7999 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8000 * </ul>
8001 *
8002 * @return The AudioTrack used for audio injection
8003 * @throws NullPointerException if AudioFormat argument is null.
8004 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8005 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8006 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8007 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8008 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8009 * or MODE_COMMUNICATION_REDIRECT.
8010 */
8011 @TestApi
8012 @SystemApi
8013 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8014 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
8015 Objects.requireNonNull(format);
8016 checkCallRedirectionFormat(format, true /* isOutput */);
8017
8018 AudioTrack track = null;
8019 int redirectMode = getCallRedirectMode();
8020 if (redirectMode == CALL_REDIRECT_NONE) {
8021 throw new IllegalStateException(
8022 " not available in mode " + AudioSystem.modeToString(getMode()));
8023 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8024 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8025 }
8026
8027 track = new AudioTrack.Builder()
8028 .setAudioAttributes(new AudioAttributes.Builder()
8029 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
8030 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
8031 .build())
8032 .setAudioFormat(format)
8033 .setCallRedirectionMode(redirectMode)
8034 .build();
8035
8036 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
8037 synchronized (mCallRedirectionLock) {
8038 if (mCallRedirectionModeListener == null) {
8039 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8040 try {
8041 addOnModeChangedListener(
8042 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8043 } catch (Exception e) {
8044 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8045 mCallRedirectionModeListener = null;
8046 throw new UnsupportedOperationException(" Cannot register mode listener ");
8047 }
8048 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8049 }
8050 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8051 info.redirectMode = redirectMode;
8052 info.trackOrRecord = new WeakReference<AudioTrack>(track);
8053 mCallIRedirectionClients.add(info);
8054 }
8055 } else {
8056 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
8057 }
8058 return track;
8059 }
8060
8061 /**
8062 * @hide
8063 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
8064 * This can be used for functions like call screening or call audio redirection and is reserved
8065 * to system apps with privileged permission.
8066 * @param format the desired audio format for audio capture.
8067 *<p>Formats accepted are:
8068 * <ul>
8069 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
8070 * <li><em>Channel mask</em> - Mono or Stereo </li>
8071 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
8072 * </ul>
8073 *
8074 * @return The AudioRecord used for audio extraction
8075 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
8076 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
8077 * @throws NullPointerException if AudioFormat argument is null.
8078 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
8079 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
8080 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
8081 * or MODE_COMMUNICATION_REDIRECT.
8082 */
8083 @TestApi
8084 @SystemApi
8085 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
8086 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
8087 Objects.requireNonNull(format);
8088 checkCallRedirectionFormat(format, false /* isOutput */);
8089
8090 AudioRecord record = null;
8091 int redirectMode = getCallRedirectMode();
8092 if (redirectMode == CALL_REDIRECT_NONE) {
8093 throw new IllegalStateException(
8094 " not available in mode " + AudioSystem.modeToString(getMode()));
8095 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
8096 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
8097 }
8098
8099 record = new AudioRecord.Builder()
8100 .setAudioAttributes(new AudioAttributes.Builder()
8101 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
8102 .build())
8103 .setAudioFormat(format)
8104 .setCallRedirectionMode(redirectMode)
8105 .build();
8106
8107 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
8108 synchronized (mCallRedirectionLock) {
8109 if (mCallRedirectionModeListener == null) {
8110 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
8111 try {
8112 addOnModeChangedListener(
8113 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
8114 } catch (Exception e) {
8115 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
8116 mCallRedirectionModeListener = null;
8117 throw new UnsupportedOperationException(" Cannot register mode listener ");
8118 }
8119 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
8120 }
8121 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
8122 info.redirectMode = redirectMode;
8123 info.trackOrRecord = new WeakReference<AudioRecord>(record);
8124 mCallIRedirectionClients.add(info);
8125 }
8126 } else {
8127 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
8128 }
8129 return record;
8130 }
8131
8132 class CallInjectionModeChangedListener implements OnModeChangedListener {
8133 @Override
8134 public void onModeChanged(@AudioMode int mode) {
8135 synchronized (mCallRedirectionLock) {
8136 final ArrayList<CallIRedirectionClientInfo> clientInfos =
8137 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
8138 for (CallIRedirectionClientInfo info : clientInfos) {
8139 Object trackOrRecord = info.trackOrRecord.get();
8140 if (trackOrRecord != null) {
8141 if ((info.redirectMode == CALL_REDIRECT_PSTN
8142 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
8143 && mode != MODE_CALL_REDIRECT)
8144 || (info.redirectMode == CALL_REDIRECT_VOIP
8145 && mode != MODE_IN_COMMUNICATION
8146 && mode != MODE_COMMUNICATION_REDIRECT)) {
8147 if (trackOrRecord instanceof AudioTrack) {
8148 AudioTrack track = (AudioTrack) trackOrRecord;
8149 track.release();
8150 } else {
8151 AudioRecord record = (AudioRecord) trackOrRecord;
8152 record.release();
8153 }
8154 mCallIRedirectionClients.remove(info);
8155 }
8156 }
8157 }
8158 if (mCallIRedirectionClients.isEmpty()) {
8159 try {
8160 if (mCallRedirectionModeListener != null) {
8161 removeOnModeChangedListener(mCallRedirectionModeListener);
8162 }
8163 } catch (Exception e) {
8164 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
8165 } finally {
8166 mCallRedirectionModeListener = null;
8167 mCallIRedirectionClients = null;
8168 }
8169 }
8170 }
8171 }
8172 }
8173
Paul McLeane3383cc2015-05-08 11:41:20 -07008174 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008175 // audio device connection-dependent muting
8176 /**
8177 * @hide
8178 * Mute a set of playback use cases until a given audio device is connected.
8179 * Automatically unmute upon connection of the device, or after the given timeout, whichever
8180 * happens first.
8181 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
8182 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
8183 * device connects
8184 * @param device the audio device expected to connect within the timeout duration
8185 * @param timeout the maximum amount of time to wait for the device connection
8186 * @param timeUnit the unit for the timeout
8187 * @throws IllegalStateException when trying to issue the command while another is already in
8188 * progress and hasn't been cancelled by
8189 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8190 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8191 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8192 */
8193 @SystemApi
8194 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8195 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8196 @NonNull AudioDeviceAttributes device,
8197 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8198 if (timeout <= 0) {
8199 throw new IllegalArgumentException("Timeout must be greater than 0");
8200 }
8201 Objects.requireNonNull(usagesToMute);
8202 if (usagesToMute.length == 0) {
8203 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8204 }
8205 Objects.requireNonNull(device);
8206 Objects.requireNonNull(timeUnit);
8207 try {
8208 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8209 } catch (RemoteException e) {
8210 throw e.rethrowFromSystemServer();
8211 }
8212 }
8213
8214 /**
8215 * @hide
8216 * Query which audio device, if any, is causing some playback use cases to be muted until it
8217 * connects.
8218 * @return the audio device used in
8219 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8220 * if there is no active muting command (either because the muting command was not issued
8221 * or because it timed out)
8222 */
8223 @SystemApi
8224 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8225 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8226 try {
8227 return getService().getMutingExpectedDevice();
8228 } catch (RemoteException e) {
8229 throw e.rethrowFromSystemServer();
8230 }
8231 }
8232
8233 /**
8234 * @hide
8235 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8236 * command.
8237 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8238 * command was issued.
8239 * @throws IllegalStateException when trying to issue the command for a device whose connection
8240 * is not anticipated by a previous call to
8241 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8242 */
8243 @SystemApi
8244 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8245 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8246 throws IllegalStateException {
8247 Objects.requireNonNull(device);
8248 try {
8249 getService().cancelMuteAwaitConnection(device);
8250 } catch (RemoteException e) {
8251 throw e.rethrowFromSystemServer();
8252 }
8253 }
8254
8255 /**
8256 * @hide
8257 * A callback class to receive events about the muting and unmuting of playback use cases
8258 * conditional on the upcoming connection of an audio device.
8259 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8260 */
8261 @SystemApi
8262 public abstract static class MuteAwaitConnectionCallback {
8263
8264 /**
8265 * An event where the expected audio device connected
8266 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8267 */
8268 public static final int EVENT_CONNECTION = 1;
8269 /**
8270 * An event where the expected audio device failed connect before the timeout happened
8271 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8272 */
8273 public static final int EVENT_TIMEOUT = 2;
8274 /**
8275 * An event where the {@code muteAwaitConnection()} command
8276 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
8277 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8278 */
8279 public static final int EVENT_CANCEL = 3;
8280
8281 /** @hide */
8282 @IntDef(flag = false, prefix = "EVENT_", value = {
8283 EVENT_CONNECTION,
8284 EVENT_TIMEOUT,
8285 EVENT_CANCEL }
8286 )
8287 @Retention(RetentionPolicy.SOURCE)
8288 public @interface UnmuteEvent {}
8289
8290 /**
8291 * Called when a number of playback use cases are muted in response to a call to
8292 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
8293 * @param device the audio device whose connection is expected. Playback use cases are
8294 * unmuted when that device connects
8295 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
8296 * playback use cases.
8297 */
8298 public void onMutedUntilConnection(
8299 @NonNull AudioDeviceAttributes device,
8300 @NonNull int[] mutedUsages) {}
8301
8302 /**
8303 * Called when an event occurred that caused playback uses cases to be unmuted
8304 * @param unmuteEvent the nature of the event
8305 * @param device the device that was expected to connect
8306 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
8307 * the event occurred
8308 */
8309 public void onUnmutedEvent(
8310 @UnmuteEvent int unmuteEvent,
8311 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
8312 }
8313
8314
8315 /**
8316 * @hide
8317 * Register a callback to receive updates on the playback muting conditional on a specific
8318 * audio device connection.
8319 * @param executor the {@link Executor} handling the callback
8320 * @param callback the callback to register
8321 */
8322 @SystemApi
8323 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8324 public void registerMuteAwaitConnectionCallback(
8325 @NonNull @CallbackExecutor Executor executor,
8326 @NonNull MuteAwaitConnectionCallback callback) {
8327 synchronized (mMuteAwaitConnectionListenerLock) {
8328 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8329 MuteAwaitConnectionDispatcherStub> res =
8330 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
8331 executor, callback, mMuteAwaitConnectionListeners,
8332 mMuteAwaitConnDispatcherStub,
8333 () -> new MuteAwaitConnectionDispatcherStub(),
8334 stub -> stub.register(true));
8335 mMuteAwaitConnectionListeners = res.first;
8336 mMuteAwaitConnDispatcherStub = res.second;
8337 }
8338 }
8339
8340 /**
8341 * @hide
8342 * Unregister a previously registered callback for playback muting conditional on device
8343 * connection.
8344 * @param callback the callback to unregister
8345 */
8346 @SystemApi
8347 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8348 public void unregisterMuteAwaitConnectionCallback(
8349 @NonNull MuteAwaitConnectionCallback callback) {
8350 synchronized (mMuteAwaitConnectionListenerLock) {
8351 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8352 MuteAwaitConnectionDispatcherStub> res =
8353 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
8354 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
8355 stub -> stub.register(false));
8356 mMuteAwaitConnectionListeners = res.first;
8357 mMuteAwaitConnDispatcherStub = res.second;
8358 }
8359 }
8360
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008361 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008362 * Add UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008363 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008364 * @param assistantUids UIDs of the services that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008365 *
8366 * @hide
8367 */
8368 @SystemApi
8369 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008370 public void addAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008371 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008372 getService().addAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008373 } catch (RemoteException e) {
8374 throw e.rethrowFromSystemServer();
8375 }
8376 }
8377
8378 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008379 * Remove UIDs that can be considered as assistant.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008380 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008381 * @param assistantUids UIDs of the services that should be remove.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008382 *
8383 * @hide
8384 */
8385 @SystemApi
8386 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008387 public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008388 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008389 getService().removeAssistantServicesUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008390 } catch (RemoteException e) {
8391 throw e.rethrowFromSystemServer();
8392 }
8393 }
8394
8395 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008396 * Get the assistants UIDs that been added with the
8397 * {@link #addAssistantServicesUids(int[])} and not yet removed with
8398 * {@link #removeAssistantServicesUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008399 *
Oscar Azucena3ae33762022-03-04 04:44:59 +00008400 * <p> Note that during native audioserver crash and after boot up the list of assistant
8401 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
8402 * Just after user switch, the list of assistant will also reset to empty.
8403 * In both cases,The component's UID of the assistiant role or assistant setting will be
8404 * automitically added to the list by the audio service.
8405 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008406 * @return array of assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008407 *
8408 * @hide
8409 */
8410 @SystemApi
8411 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008412 public @NonNull int[] getAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008413 try {
8414 int[] uids = getService().getAssistantServicesUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00008415 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008416 } catch (RemoteException e) {
8417 throw e.rethrowFromSystemServer();
8418 }
8419 }
8420
8421 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008422 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
8423 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
8424 * In this manner calling the API with an empty array will remove all UIDs previously set.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008425 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008426 * @param assistantUids UIDs of the services that can be considered active assistant. Can be
8427 * an empty array, for this no UID will be considered active.
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008428 *
8429 * <p> Note that during audio service crash reset and after boot up the list of active assistant
Oscar Azucena88467fe2022-02-15 21:55:11 +00008430 * UIDs will be reset to an empty list (i.e. no UID will be considered as an active assistant).
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008431 * Just after user switch the list of active assistant will also reset to empty.
8432 *
8433 * @hide
8434 */
8435 @SystemApi
8436 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008437 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008438 try {
Oscar Azucena88467fe2022-02-15 21:55:11 +00008439 getService().setActiveAssistantServiceUids(assistantUids);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008440 } catch (RemoteException e) {
8441 throw e.rethrowFromSystemServer();
8442 }
8443 }
8444
8445 /**
Oscar Azucena88467fe2022-02-15 21:55:11 +00008446 * Get active assistant UIDs last set with the
8447 * {@link #setActiveAssistantServiceUids(int[])}
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008448 *
Oscar Azucena88467fe2022-02-15 21:55:11 +00008449 * @return array of active assistants UIDs
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008450 *
8451 * @hide
8452 */
8453 @SystemApi
8454 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Oscar Azucena88467fe2022-02-15 21:55:11 +00008455 public @NonNull int[] getActiveAssistantServicesUids() {
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008456 try {
8457 int[] uids = getService().getActiveAssistantServiceUids();
Oscar Azucena88467fe2022-02-15 21:55:11 +00008458 return Arrays.copyOf(uids, uids.length);
Oscar Azucena3ef3f582022-01-31 19:07:14 -08008459 } catch (RemoteException e) {
8460 throw e.rethrowFromSystemServer();
8461 }
8462 }
8463
jiabinfe6b7f12022-02-04 18:45:44 +00008464 /**
8465 * Returns the audio HAL version in the form MAJOR.MINOR. If there is no audio HAL found, null
8466 * will be returned.
8467 *
8468 * @hide
8469 */
8470 @TestApi
8471 public static @Nullable String getHalVersion() {
8472 try {
8473 return getService().getHalVersion();
8474 } catch (RemoteException e) {
8475 Log.e(TAG, "Error querying getHalVersion", e);
8476 throw e.rethrowFromSystemServer();
8477 }
8478 }
8479
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08008480 private final Object mMuteAwaitConnectionListenerLock = new Object();
8481
8482 @GuardedBy("mMuteAwaitConnectionListenerLock")
8483 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
8484 mMuteAwaitConnectionListeners;
8485
8486 @GuardedBy("mMuteAwaitConnectionListenerLock")
8487 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
8488
8489 private final class MuteAwaitConnectionDispatcherStub
8490 extends IMuteAwaitConnectionCallback.Stub {
8491 public void register(boolean register) {
8492 try {
8493 getService().registerMuteAwaitConnectionDispatcher(this, register);
8494 } catch (RemoteException e) {
8495 throw e.rethrowFromSystemServer();
8496 }
8497 }
8498
8499 @Override
8500 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8501 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
8502 int[] mutedUsages) {
8503 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8504 mMuteAwaitConnectionListenerLock,
8505 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
8506 }
8507
8508 @Override
8509 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8510 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
8511 int[] mutedUsages) {
8512 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8513 mMuteAwaitConnectionListenerLock,
8514 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
8515 }
8516 }
8517
8518 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07008519 // Inner classes
8520 //--------------------
8521 /**
8522 * Helper class to handle the forwarding of native events to the appropriate listener
8523 * (potentially) handled in a different thread.
8524 */
8525 private class NativeEventHandlerDelegate {
8526 private final Handler mHandler;
8527
Paul McLean03346882015-05-12 15:36:56 -07008528 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07008529 Handler handler) {
8530 // find the looper for our new event handler
8531 Looper looper;
8532 if (handler != null) {
8533 looper = handler.getLooper();
8534 } else {
8535 // no given handler, use the looper the addListener call was called in
8536 looper = Looper.getMainLooper();
8537 }
8538
8539 // construct the event handler with this looper
8540 if (looper != null) {
8541 // implement the event handler delegate
8542 mHandler = new Handler(looper) {
8543 @Override
8544 public void handleMessage(Message msg) {
8545 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07008546 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07008547 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07008548 if (callback != null) {
8549 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07008550 }
8551 break;
Paul McLean03346882015-05-12 15:36:56 -07008552
8553 case MSG_DEVICES_DEVICES_REMOVED:
8554 if (callback != null) {
8555 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
8556 }
8557 break;
8558
Paul McLeane3383cc2015-05-08 11:41:20 -07008559 default:
8560 Log.e(TAG, "Unknown native event type: " + msg.what);
8561 break;
8562 }
8563 }
8564 };
8565 } else {
8566 mHandler = null;
8567 }
8568 }
8569
8570 Handler getHandler() {
8571 return mHandler;
8572 }
8573 }
Carter Hsu2065d1e2022-01-19 19:54:50 +08008574}