blob: e6cba660390733b96f01c2d023a7dcf4d3ad5c66 [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;
Eric Laurent1c3408f2021-11-09 12:09:54 +010036import android.compat.annotation.ChangeId;
37import android.compat.annotation.EnabledSince;
Artur Satayev53fe9662019-12-10 17:47:55 +000038import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070039import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070041import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080042import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080043import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070044import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080045import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070046import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070047import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020048import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080049import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070050import android.media.session.MediaController;
51import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070052import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070053import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070054import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070056import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.os.Handler;
58import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080059import android.os.Looper;
60import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.os.RemoteException;
62import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050063import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010064import android.os.UserHandle;
jiabinc0f49442018-01-05 10:23:50 -080065import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070066import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080068import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070069import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080071import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020072import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080073
jiabinc0f49442018-01-05 10:23:50 -080074import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080075import java.lang.annotation.Retention;
76import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070077import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080078import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070079import java.util.Arrays;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080080import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070081import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090082import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080083import java.util.List;
jiabin39940752018-04-02 18:18:45 -070084import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070085import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090086import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070087import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080088import java.util.concurrent.Executor;
89
Eric Laurent700e7342014-05-02 18:33:15 -070090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091/**
92 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060094@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095public class AudioManager {
96
Marco Nelissen29f16932015-04-17 09:50:56 -070097 private Context mOriginalContext;
98 private Context mApplicationContext;
Joe Onorato86f67862010-11-05 18:57:34 -070099 private long mVolumeKeyUpTime;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800100 private static final String TAG = "AudioManager";
101 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800102 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200103 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
104 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
jiabin0f3339c2021-07-09 11:50:07 -0700106 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /**
109 * Broadcast intent, a hint for applications that audio is about to become
110 * 'noisy' due to a change in audio outputs. For example, this intent may
111 * be sent when a wired headset is unplugged, or when an A2DP audio
112 * sink is disconnected, and the audio system is about to automatically
113 * switch audio route to the speaker. Applications that are controlling
114 * audio streams may consider pausing, reducing volume or some other action
115 * on receipt of this intent so as not to surprise the user with audio
116 * from the speaker.
117 */
118 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
119 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
120
121 /**
122 * Sticky broadcast intent action indicating that the ringer mode has
123 * changed. Includes the new ringer mode.
124 *
125 * @see #EXTRA_RINGER_MODE
126 */
127 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
128 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
129
130 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500131 * @hide
132 * Sticky broadcast intent action indicating that the internal ringer mode has
133 * changed. Includes the new ringer mode.
134 *
135 * @see #EXTRA_RINGER_MODE
136 */
137 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
138 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
139 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
140
141 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 * The new ringer mode.
143 *
144 * @see #RINGER_MODE_CHANGED_ACTION
145 * @see #RINGER_MODE_NORMAL
146 * @see #RINGER_MODE_SILENT
147 * @see #RINGER_MODE_VIBRATE
148 */
149 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
150
151 /**
152 * Broadcast intent action indicating that the vibrate setting has
153 * changed. Includes the vibrate type and its new setting.
154 *
155 * @see #EXTRA_VIBRATE_TYPE
156 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700157 * @deprecated Applications should maintain their own vibrate policy based on
158 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 */
160 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500161 public static final String VIBRATE_SETTING_CHANGED_ACTION =
162 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
164 /**
165 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700166 * Includes the stream, the new volume and previous volumes.
167 * Notes:
168 * - for internal platform use only, do not make public,
169 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 *
171 * @see #EXTRA_VOLUME_STREAM_TYPE
172 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800173 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 */
175 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100176 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
178
179 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400180 * @hide Broadcast intent when the devices for a particular stream type changes.
181 * Includes the stream, the new devices and previous devices.
182 * Notes:
183 * - for internal platform use only, do not make public,
184 * - never used for "remote" volume changes
185 *
186 * @see #EXTRA_VOLUME_STREAM_TYPE
187 * @see #EXTRA_VOLUME_STREAM_DEVICES
188 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
189 * @see #getDevicesForStream
190 */
191 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
192 public static final String STREAM_DEVICES_CHANGED_ACTION =
193 "android.media.STREAM_DEVICES_CHANGED_ACTION";
194
195 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800196 * @hide Broadcast intent when a stream mute state changes.
197 * Includes the stream that changed and the new mute state
198 *
199 * @see #EXTRA_VOLUME_STREAM_TYPE
200 * @see #EXTRA_STREAM_VOLUME_MUTED
201 */
202 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
203 public static final String STREAM_MUTE_CHANGED_ACTION =
204 "android.media.STREAM_MUTE_CHANGED_ACTION";
205
206 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500207 * @hide Broadcast intent when the master mute state changes.
208 * Includes the the new volume
209 *
210 * @see #EXTRA_MASTER_VOLUME_MUTED
211 */
212 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
213 public static final String MASTER_MUTE_CHANGED_ACTION =
214 "android.media.MASTER_MUTE_CHANGED_ACTION";
215
216 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 * The new vibrate setting for a particular type.
218 *
219 * @see #VIBRATE_SETTING_CHANGED_ACTION
220 * @see #EXTRA_VIBRATE_TYPE
221 * @see #VIBRATE_SETTING_ON
222 * @see #VIBRATE_SETTING_OFF
223 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700224 * @deprecated Applications should maintain their own vibrate policy based on
225 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 */
227 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
228
229 /**
230 * The vibrate type whose setting has changed.
231 *
232 * @see #VIBRATE_SETTING_CHANGED_ACTION
233 * @see #VIBRATE_TYPE_NOTIFICATION
234 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700235 * @deprecated Applications should maintain their own vibrate policy based on
236 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 */
238 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
239
240 /**
241 * @hide The stream type for the volume changed intent.
242 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100243 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
245
246 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700247 * @hide
248 * The stream type alias for the volume changed intent.
249 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
250 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
251 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
252 * {@link #STREAM_MUSIC} on others (e.g. a television).
253 */
254 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
255 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
256
257 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 * @hide The volume associated with the stream for the volume changed intent.
259 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100260 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 public static final String EXTRA_VOLUME_STREAM_VALUE =
262 "android.media.EXTRA_VOLUME_STREAM_VALUE";
263
Eric Laurent9ce379a2010-02-16 06:00:26 -0800264 /**
265 * @hide The previous volume associated with the stream for the volume changed intent.
266 */
267 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
268 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
269
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500270 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400271 * @hide The devices associated with the stream for the stream devices changed intent.
272 */
273 public static final String EXTRA_VOLUME_STREAM_DEVICES =
274 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
275
276 /**
277 * @hide The previous devices associated with the stream for the stream devices changed intent.
278 */
279 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
280 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
281
282 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500283 * @hide The new master volume mute state for the master mute changed intent.
284 * Value is boolean
285 */
286 public static final String EXTRA_MASTER_VOLUME_MUTED =
287 "android.media.EXTRA_MASTER_VOLUME_MUTED";
288
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700289 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800290 * @hide The new stream volume mute state for the stream mute changed intent.
291 * Value is boolean
292 */
293 public static final String EXTRA_STREAM_VOLUME_MUTED =
294 "android.media.EXTRA_STREAM_VOLUME_MUTED";
295
296 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700297 * Broadcast Action: Wired Headset plugged in or unplugged.
298 *
299 * You <em>cannot</em> receive this through components declared
300 * in manifests, only by explicitly registering for it with
301 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
302 * Context.registerReceiver()}.
303 *
304 * <p>The intent will have the following extra values:
305 * <ul>
306 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
307 * <li><em>name</em> - Headset type, human readable string </li>
308 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
309 * </ul>
310 * </ul>
311 */
312 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
313 public static final String ACTION_HEADSET_PLUG =
314 "android.intent.action.HEADSET_PLUG";
315
316 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200317 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700318 *
319 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
320 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
321 * <p>It can only be received by explicitly registering for it with
322 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
323 */
324 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
325 public static final String ACTION_HDMI_AUDIO_PLUG =
326 "android.media.action.HDMI_AUDIO_PLUG";
327
328 /**
329 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
330 * or unplugged.
331 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
332 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700333 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700334
335 /**
336 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
337 * supported by the HDMI device.
338 * The corresponding integer value is only available when the device is plugged in (as expressed
339 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
340 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700341 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700342
343 /**
344 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
345 * the connected HDMI device.
346 * The corresponding array of encoding values is only available when the device is plugged in
347 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
348 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
349 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
350 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700351 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700352
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700353 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700355 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700357 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700359 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700361 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700363 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700365 /** @hide Used to identify the volume of audio streams for phone calls when connected
366 * to bluetooth */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100367 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700369 /** @hide Used to identify the volume of audio streams for enforced system sounds
370 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100371 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700372 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700373 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700374 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700375 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
376 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100377 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700378 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800379 /** Used to identify the volume of audio streams for accessibility prompts */
380 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000381 /** @hide Used to identify the volume of audio streams for virtual assistant */
382 @SystemApi
383 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
384 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 /** Number of audio streams */
387 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700388 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 */
Eric Laurenta553c252009-07-17 12:17:14 -0700390 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391
Paul McLeand6f87c82021-03-31 13:02:41 -0600392 /** @hide */
393 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
394 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
395 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
396 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
397
398 /** @hide */
399 @TestApi
400 public static final int[] getPublicStreamTypes() {
401 return PUBLIC_STREAM_TYPES;
402 }
403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 /**
405 * Increase the ringer volume.
406 *
407 * @see #adjustVolume(int, int)
408 * @see #adjustStreamVolume(int, int, int)
409 */
410 public static final int ADJUST_RAISE = 1;
411
412 /**
413 * Decrease the ringer volume.
414 *
415 * @see #adjustVolume(int, int)
416 * @see #adjustStreamVolume(int, int, int)
417 */
418 public static final int ADJUST_LOWER = -1;
419
420 /**
421 * Maintain the previous ringer volume. This may be useful when needing to
422 * show the volume toast without actually modifying the volume.
423 *
424 * @see #adjustVolume(int, int)
425 * @see #adjustStreamVolume(int, int, int)
426 */
427 public static final int ADJUST_SAME = 0;
428
RoboErik4197cb62015-01-21 15:45:32 -0800429 /**
430 * Mute the volume. Has no effect if the stream is already muted.
431 *
432 * @see #adjustVolume(int, int)
433 * @see #adjustStreamVolume(int, int, int)
434 */
435 public static final int ADJUST_MUTE = -100;
436
437 /**
438 * Unmute the volume. Has no effect if the stream is not muted.
439 *
440 * @see #adjustVolume(int, int)
441 * @see #adjustStreamVolume(int, int, int)
442 */
443 public static final int ADJUST_UNMUTE = 100;
444
445 /**
446 * Toggle the mute state. If muted the stream will be unmuted. If not muted
447 * the stream will be muted.
448 *
449 * @see #adjustVolume(int, int)
450 * @see #adjustStreamVolume(int, int, int)
451 */
452 public static final int ADJUST_TOGGLE_MUTE = 101;
453
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700454 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800455 @IntDef(flag = false, prefix = "ADJUST", value = {
456 ADJUST_RAISE,
457 ADJUST_LOWER,
458 ADJUST_SAME,
459 ADJUST_MUTE,
460 ADJUST_UNMUTE,
461 ADJUST_TOGGLE_MUTE }
462 )
463 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800464 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800465
466 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700467 public static final String adjustToString(int adj) {
468 switch (adj) {
469 case ADJUST_RAISE: return "ADJUST_RAISE";
470 case ADJUST_LOWER: return "ADJUST_LOWER";
471 case ADJUST_SAME: return "ADJUST_SAME";
472 case ADJUST_MUTE: return "ADJUST_MUTE";
473 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
474 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
475 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
476 }
477 }
478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 // Flags should be powers of 2!
480
481 /**
482 * Show a toast containing the current volume.
483 *
484 * @see #adjustStreamVolume(int, int, int)
485 * @see #adjustVolume(int, int)
486 * @see #setStreamVolume(int, int, int)
487 * @see #setRingerMode(int)
488 */
489 public static final int FLAG_SHOW_UI = 1 << 0;
490
491 /**
492 * Whether to include ringer modes as possible options when changing volume.
493 * For example, if true and volume level is 0 and the volume is adjusted
494 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
495 * vibrate mode.
496 * <p>
497 * By default this is on for the ring stream. If this flag is included,
498 * this behavior will be present regardless of the stream type being
499 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700500 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 * @see #adjustVolume(int, int)
502 * @see #adjustStreamVolume(int, int, int)
503 */
504 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
505
506 /**
507 * Whether to play a sound when changing the volume.
508 * <p>
509 * If this is given to {@link #adjustVolume(int, int)} or
510 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
511 * in some cases (for example, the decided stream type is not
512 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
513 * downward).
514 *
515 * @see #adjustStreamVolume(int, int, int)
516 * @see #adjustVolume(int, int)
517 * @see #setStreamVolume(int, int, int)
518 */
519 public static final int FLAG_PLAY_SOUND = 1 << 2;
520
521 /**
522 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
523 * changing volume).
524 */
525 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
526
527 /**
528 * Whether to vibrate if going into the vibrate ringer mode.
529 */
530 public static final int FLAG_VIBRATE = 1 << 4;
531
532 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700533 * Indicates to VolumePanel that the volume slider should be disabled as user
534 * cannot change the stream volume
535 * @hide
536 */
537 public static final int FLAG_FIXED_VOLUME = 1 << 5;
538
539 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700540 * Indicates the volume set/adjust call is for Bluetooth absolute volume
541 * @hide
542 */
543 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
544
545 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400546 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
547 * @hide
548 */
549 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
550
551 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900552 * Indicates the volume call is for Hdmi Cec system audio volume
553 * @hide
554 */
555 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
556
557 /**
RoboErik3c45c292014-07-08 16:47:31 -0700558 * Indicates that this should only be handled if media is actively playing.
559 * @hide
560 */
561 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
562
563 /**
John Spurlock35134602014-07-24 18:10:48 -0400564 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
565 * @hide
566 */
567 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
568
569 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500570 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
571 * @hide
572 */
573 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
574
John Spurlockb94f2d62015-03-17 14:11:57 -0400575 /**
576 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900577 * This flag can be used in the places in order to denote (or check) that a volume adjustment
578 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400579 * @hide
580 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900581 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900582 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400583
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900584 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100585 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200586 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100587 ENCODED_SURROUND_OUTPUT_AUTO,
588 ENCODED_SURROUND_OUTPUT_NEVER,
589 ENCODED_SURROUND_OUTPUT_ALWAYS,
590 ENCODED_SURROUND_OUTPUT_MANUAL
591 })
592 @Retention(RetentionPolicy.SOURCE)
593 public @interface EncodedSurroundOutputMode {}
594
595 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200596 * The mode for surround sound formats is unknown.
597 */
598 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
599
600 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100601 * The surround sound formats are available for use if they are detected. This is the default
602 * mode.
603 */
604 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
605
606 /**
607 * The surround sound formats are NEVER available, even if they are detected by the hardware.
608 * Those formats will not be reported.
609 */
610 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
611
612 /**
613 * The surround sound formats are ALWAYS available, even if they are not detected by the
614 * hardware. Those formats will be reported as part of the HDMI output capability.
615 * Applications are then free to use either PCM or encoded output.
616 */
617 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
618
619 /**
620 * Surround sound formats are available according to the choice of user, even if they are not
621 * detected by the hardware. Those formats will be reported as part of the HDMI output
622 * capability. Applications are then free to use either PCM or encoded output.
623 */
624 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
625
626 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900627 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900628 FLAG_SHOW_UI,
629 FLAG_ALLOW_RINGER_MODES,
630 FLAG_PLAY_SOUND,
631 FLAG_REMOVE_SOUND_AND_VIBRATE,
632 FLAG_VIBRATE,
633 FLAG_FIXED_VOLUME,
634 FLAG_BLUETOOTH_ABS_VOLUME,
635 FLAG_SHOW_SILENT_HINT,
636 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
637 FLAG_ACTIVE_MEDIA_ONLY,
638 FLAG_SHOW_UI_WARNINGS,
639 FLAG_SHOW_VIBRATE_HINT,
640 FLAG_FROM_KEY,
641 })
642 @Retention(RetentionPolicy.SOURCE)
643 public @interface Flags {}
644
Hyundo Moonca0080d2018-12-26 16:16:55 +0900645 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
646 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
647
648 static {
649 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
650 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
651 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
652 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
653 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
654 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
655 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
656 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
657 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
658 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
659 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
660 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
661 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
662 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500663
664 /** @hide */
665 public static String flagsToString(int flags) {
666 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900667 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
668 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500669 if ((flags & flag) != 0) {
670 if (sb.length() > 0) {
671 sb.append(',');
672 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900673 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500674 flags &= ~flag;
675 }
676 }
677 if (flags != 0) {
678 if (sb.length() > 0) {
679 sb.append(',');
680 }
681 sb.append(flags);
682 }
683 return sb.toString();
684 }
685
686 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 * Ringer mode that will be silent and will not vibrate. (This overrides the
688 * vibrate setting.)
689 *
690 * @see #setRingerMode(int)
691 * @see #getRingerMode()
692 */
693 public static final int RINGER_MODE_SILENT = 0;
694
695 /**
696 * Ringer mode that will be silent and will vibrate. (This will cause the
697 * phone ringer to always vibrate, but the notification vibrate to only
698 * vibrate if set.)
699 *
700 * @see #setRingerMode(int)
701 * @see #getRingerMode()
702 */
703 public static final int RINGER_MODE_VIBRATE = 1;
704
705 /**
706 * Ringer mode that may be audible and may vibrate. It will be audible if
707 * the volume before changing out of this mode was audible. It will vibrate
708 * if the vibrate setting is on.
709 *
710 * @see #setRingerMode(int)
711 * @see #getRingerMode()
712 */
713 public static final int RINGER_MODE_NORMAL = 2;
714
John Spurlock97559372014-10-24 16:27:36 -0400715 /**
716 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
717 * @hide
718 */
719 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 /**
722 * Vibrate type that corresponds to the ringer.
723 *
724 * @see #setVibrateSetting(int, int)
725 * @see #getVibrateSetting(int)
726 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700727 * @deprecated Applications should maintain their own vibrate policy based on
728 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 */
730 public static final int VIBRATE_TYPE_RINGER = 0;
731
732 /**
733 * Vibrate type that corresponds to notifications.
734 *
735 * @see #setVibrateSetting(int, int)
736 * @see #getVibrateSetting(int)
737 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700738 * @deprecated Applications should maintain their own vibrate policy based on
739 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 */
741 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
742
743 /**
744 * Vibrate setting that suggests to never vibrate.
745 *
746 * @see #setVibrateSetting(int, int)
747 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700748 * @deprecated Applications should maintain their own vibrate policy based on
749 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 */
751 public static final int VIBRATE_SETTING_OFF = 0;
752
753 /**
754 * Vibrate setting that suggests to vibrate when possible.
755 *
756 * @see #setVibrateSetting(int, int)
757 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700758 * @deprecated Applications should maintain their own vibrate policy based on
759 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 */
761 public static final int VIBRATE_SETTING_ON = 1;
762
763 /**
764 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
765 * mode.
766 *
767 * @see #setVibrateSetting(int, int)
768 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700769 * @deprecated Applications should maintain their own vibrate policy based on
770 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 */
772 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
773
774 /**
775 * Suggests using the default stream type. This may not be used in all
776 * places a stream type is needed.
777 */
778 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
779
780 private static IAudioService sService;
781
782 /**
783 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800784 * For test purposes only, will throw NPE with some methods that require a Context.
785 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000786 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800787 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800788 }
789
790 /**
791 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100793 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700795 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 }
797
Marco Nelissen29f16932015-04-17 09:50:56 -0700798 private Context getContext() {
799 if (mApplicationContext == null) {
800 setContext(mOriginalContext);
801 }
802 if (mApplicationContext != null) {
803 return mApplicationContext;
804 }
805 return mOriginalContext;
806 }
807
808 private void setContext(Context context) {
809 mApplicationContext = context.getApplicationContext();
810 if (mApplicationContext != null) {
811 mOriginalContext = null;
812 } else {
813 mOriginalContext = context;
814 }
jiabin0f3339c2021-07-09 11:50:07 -0700815 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700816 }
817
Mathew Inwood31a792a2018-08-17 08:54:26 +0100818 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700819 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 {
821 if (sService != null) {
822 return sService;
823 }
824 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
825 sService = IAudioService.Stub.asInterface(b);
826 return sService;
827 }
828
829 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700830 * Sends a simulated key event for a media button.
831 * To simulate a key press, you must first send a KeyEvent built with a
832 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
833 * action.
834 * <p>The key event will be sent to the current media key event consumer which registered with
835 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
836 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
837 * {@link KeyEvent#KEYCODE_MUTE},
838 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
839 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
840 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
841 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
842 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
843 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
844 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
845 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
846 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
847 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
848 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
849 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
850 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700851 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700852 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700853 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700854 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700855 }
856
857 /**
858 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700859 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800860 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700861 /*
862 * If the user hits another key within the play sound delay, then
863 * cancel the sound
864 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800865 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700866 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
867 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500868 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700869 /*
870 * The user has hit another key during the delay (e.g., 300ms)
871 * since the last volume key up, so cancel any sounds.
872 */
John Spurlockee5ad722015-03-03 16:17:21 -0500873 adjustSuggestedStreamVolume(ADJUST_SAME,
874 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700875 }
876 }
877
878 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700879 * Indicates if the device implements a fixed volume policy.
880 * <p>Some devices may not have volume control and may operate at a fixed volume,
881 * and may not enable muting or changing the volume of audio streams.
882 * This method will return true on such devices.
883 * <p>The following APIs have no effect when volume is fixed:
884 * <ul>
885 * <li> {@link #adjustVolume(int, int)}
886 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
887 * <li> {@link #adjustStreamVolume(int, int, int)}
888 * <li> {@link #setStreamVolume(int, int, int)}
889 * <li> {@link #setRingerMode(int)}
890 * <li> {@link #setStreamSolo(int, boolean)}
891 * <li> {@link #setStreamMute(int, boolean)}
892 * </ul>
893 */
894 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700895 boolean res = false;
896 try {
897 res = getService().isVolumeFixed();
898 } catch (RemoteException e) {
899 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700900 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700901 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700902 }
903
904 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700906 * <p>
907 * This method should only be used by applications that replace the platform-wide
908 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700909 * <p>This method has no effect if the device implements a fixed volume policy
910 * as indicated by {@link #isVolumeFixed()}.
911 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
912 * unless the app has been granted Do Not Disturb Access.
913 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 *
915 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800916 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
917 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 * @param direction The direction to adjust the volume. One of
919 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
920 * {@link #ADJUST_SAME}.
921 * @param flags One or more flags.
922 * @see #adjustVolume(int, int)
923 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700924 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
925 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 */
927 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700928 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 try {
John Wu4f7e5102021-06-22 17:29:11 +0000930 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
931 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700933 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 }
935 }
936
937 /**
938 * Adjusts the volume of the most relevant stream. For example, if a call is
939 * active, it will have the highest priority regardless of if the in-call
940 * screen is showing. Another example, if music is playing in the background
941 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700942 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800943 * This method should only be used by applications that replace the
944 * platform-wide management of audio settings or the main telephony
945 * application.
946 * <p>
947 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700948 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800949 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800951 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
952 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
953 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 * @param flags One or more flags.
955 * @see #adjustSuggestedStreamVolume(int, int, int)
956 * @see #adjustStreamVolume(int, int, int)
957 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700958 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 */
960 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700961 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500962 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 }
964
965 /**
966 * Adjusts the volume of the most relevant stream, or the given fallback
967 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700968 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800969 * This method should only be used by applications that replace the
970 * platform-wide management of audio settings or the main telephony
971 * application.
972 * <p>
973 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700974 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800975 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800977 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
978 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
979 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -0800981 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
982 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 * @param flags One or more flags.
984 * @see #adjustVolume(int, int)
985 * @see #adjustStreamVolume(int, int, int)
986 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700987 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 */
989 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700990 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500991 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400992 }
993
John Spurlockee5ad722015-03-03 16:17:21 -0500994 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100995 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -0700996 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -0500997 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700998 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400999 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001000 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001001 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001002 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001003 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 }
1005 }
1006
1007 /**
1008 * Returns the current ringtone mode.
1009 *
1010 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1011 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1012 * @see #setRingerMode(int)
1013 */
1014 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001015 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001017 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001019 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 }
1021 }
1022
1023 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001024 * Checks valid ringer mode values.
1025 *
1026 * @return true if the ringer mode indicated is valid, false otherwise.
1027 *
1028 * @see #setRingerMode(int)
1029 * @hide
1030 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001031 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001032 public static boolean isValidRingerMode(int ringerMode) {
1033 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1034 return false;
1035 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001036 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001037 try {
1038 return service.isValidRingerMode(ringerMode);
1039 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001040 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001041 }
Eric Laurent72668b22011-07-19 16:04:27 -07001042 }
1043
1044 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 * Returns the maximum volume index for a particular stream.
1046 *
1047 * @param streamType The stream type whose maximum volume index is returned.
1048 * @return The maximum valid volume index for the stream.
1049 * @see #getStreamVolume(int)
1050 */
1051 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001052 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001054 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001056 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
1058 }
1059
1060 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001061 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001062 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1063 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1064 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1065 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1066 * @return The minimum valid volume index for the stream.
1067 * @see #getStreamVolume(int)
1068 */
1069 public int getStreamMinVolume(int streamType) {
1070 if (!isPublicStreamType(streamType)) {
1071 throw new IllegalArgumentException("Invalid stream type " + streamType);
1072 }
1073 return getStreamMinVolumeInt(streamType);
1074 }
1075
1076 /**
1077 * @hide
1078 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001079 * @param streamType The stream type whose minimum volume index is returned.
1080 * @return The minimum valid volume index for the stream.
1081 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001082 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001083 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001084 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001085 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001086 try {
1087 return service.getStreamMinVolume(streamType);
1088 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001089 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001090 }
1091 }
1092
1093 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 * Returns the current volume index for a particular stream.
1095 *
1096 * @param streamType The stream type whose volume index is returned.
1097 * @return The current volume index for the stream.
1098 * @see #getStreamMaxVolume(int)
1099 * @see #setStreamVolume(int, int, int)
1100 */
1101 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001102 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001104 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001106 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
1108 }
1109
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001110 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1111 private static final float VOLUME_MIN_DB = -758.0f;
1112
1113 /** @hide */
1114 @IntDef(flag = false, prefix = "STREAM", value = {
1115 STREAM_VOICE_CALL,
1116 STREAM_SYSTEM,
1117 STREAM_RING,
1118 STREAM_MUSIC,
1119 STREAM_ALARM,
1120 STREAM_NOTIFICATION,
1121 STREAM_DTMF,
1122 STREAM_ACCESSIBILITY }
1123 )
1124 @Retention(RetentionPolicy.SOURCE)
1125 public @interface PublicStreamTypes {}
1126
1127 /**
1128 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1129 * the given type of audio output device.
1130 * @param streamType stream type for which the volume is queried.
1131 * @param index the volume index for which the volume is queried. The index value must be
1132 * between the minimum and maximum index values for the given stream type (see
1133 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1134 * @param deviceType the type of audio output device for which volume is queried.
1135 * @return a volume expressed in dB.
1136 * A negative value indicates the audio signal is attenuated. A typical maximum value
1137 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1138 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1139 */
1140 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1141 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1142 if (!isPublicStreamType(streamType)) {
1143 throw new IllegalArgumentException("Invalid stream type " + streamType);
1144 }
1145 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1146 throw new IllegalArgumentException("Invalid stream volume index " + index);
1147 }
1148 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1149 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1150 }
1151 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1152 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1153 if (gain <= VOLUME_MIN_DB) {
1154 return Float.NEGATIVE_INFINITY;
1155 } else {
1156 return gain;
1157 }
1158 }
1159
1160 private static boolean isPublicStreamType(int streamType) {
1161 switch (streamType) {
1162 case STREAM_VOICE_CALL:
1163 case STREAM_SYSTEM:
1164 case STREAM_RING:
1165 case STREAM_MUSIC:
1166 case STREAM_ALARM:
1167 case STREAM_NOTIFICATION:
1168 case STREAM_DTMF:
1169 case STREAM_ACCESSIBILITY:
1170 return true;
1171 default:
1172 return false;
1173 }
1174 }
1175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001177 * Get last audible volume before stream was muted.
1178 *
1179 * @hide
1180 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001181 @UnsupportedAppUsage
Eric Laurent25101b02011-02-02 09:33:30 -08001182 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001183 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001184 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001185 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001186 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001187 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001188 }
1189 }
1190
1191 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001192 * Get the stream type whose volume is driving the UI sounds volume.
1193 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001194 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001195 * @hide
1196 */
John Spurlockee5ad722015-03-03 16:17:21 -05001197 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001198 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001199 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001200 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001201 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001202 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001203 }
1204 }
1205
1206 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 * Sets the ringer mode.
1208 * <p>
1209 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1210 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1211 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001212 * <p>This method has no effect if the device implements a fixed volume policy
1213 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001214 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1215 * unless the app has been granted Do Not Disturb Access.
1216 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1218 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1219 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001220 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 */
1222 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001223 if (!isValidRingerMode(ringerMode)) {
1224 return;
1225 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001226 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001228 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001230 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 }
1232 }
1233
1234 /**
1235 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001236 * <p>This method has no effect if the device implements a fixed volume policy
1237 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001238 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1239 * the app has been granted Do Not Disturb Access.
1240 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 * @param streamType The stream whose volume index should be set.
1242 * @param index The volume index to set. See
1243 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1244 * @param flags One or more flags.
1245 * @see #getStreamMaxVolume(int)
1246 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001247 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001248 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1249 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 */
1251 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001252 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 try {
John Wu4f7e5102021-06-22 17:29:11 +00001254 service.setStreamVolumeWithAttribution(streamType, index, flags,
1255 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001257 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 }
1259 }
1260
1261 /**
François Gaffie9c362102018-09-21 17:43:52 +02001262 * Sets the volume index for a particular {@link AudioAttributes}.
1263 * @param attr The {@link AudioAttributes} whose volume index should be set.
1264 * @param index The volume index to set. See
1265 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1266 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1267 * @param flags One or more flags.
1268 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1269 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1270 * @see #isVolumeFixed()
1271 * @hide
1272 */
1273 @SystemApi
1274 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1275 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1276 Preconditions.checkNotNull(attr, "attr must not be null");
1277 final IAudioService service = getService();
1278 try {
1279 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001280 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001281 } catch (RemoteException e) {
1282 throw e.rethrowFromSystemServer();
1283 }
1284 }
1285
1286 /**
1287 * Returns the current volume index for a particular {@link AudioAttributes}.
1288 *
1289 * @param attr The {@link AudioAttributes} whose volume index is returned.
1290 * @return The current volume index for the stream.
1291 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1292 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1293 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1294 * @hide
1295 */
1296 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001297 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001298 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1299 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1300 Preconditions.checkNotNull(attr, "attr must not be null");
1301 final IAudioService service = getService();
1302 try {
1303 return service.getVolumeIndexForAttributes(attr);
1304 } catch (RemoteException e) {
1305 throw e.rethrowFromSystemServer();
1306 }
1307 }
1308
1309 /**
1310 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1311 *
1312 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1313 * @return The maximum valid volume index for the {@link AudioAttributes}.
1314 * @see #getVolumeIndexForAttributes(AudioAttributes)
1315 * @hide
1316 */
1317 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001318 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001319 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1320 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1321 Preconditions.checkNotNull(attr, "attr must not be null");
1322 final IAudioService service = getService();
1323 try {
1324 return service.getMaxVolumeIndexForAttributes(attr);
1325 } catch (RemoteException e) {
1326 throw e.rethrowFromSystemServer();
1327 }
1328 }
1329
1330 /**
1331 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1332 *
1333 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1334 * @return The minimum valid volume index for the {@link AudioAttributes}.
1335 * @see #getVolumeIndexForAttributes(AudioAttributes)
1336 * @hide
1337 */
1338 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001339 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001340 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1341 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1342 Preconditions.checkNotNull(attr, "attr must not be null");
1343 final IAudioService service = getService();
1344 try {
1345 return service.getMinVolumeIndexForAttributes(attr);
1346 } catch (RemoteException e) {
1347 throw e.rethrowFromSystemServer();
1348 }
1349 }
1350
1351 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001352 * Set the system usages to be supported on this device.
1353 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1354 * @hide
1355 */
1356 @SystemApi
1357 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1358 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1359 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1360 final IAudioService service = getService();
1361 try {
1362 service.setSupportedSystemUsages(systemUsages);
1363 } catch (RemoteException e) {
1364 throw e.rethrowFromSystemServer();
1365 }
1366 }
1367
1368 /**
1369 * Get the system usages supported on this device.
1370 * @return array of supported system usages {@link AttributeSystemUsage}
1371 * @hide
1372 */
1373 @SystemApi
1374 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1375 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1376 final IAudioService service = getService();
1377 try {
1378 return service.getSupportedSystemUsages();
1379 } catch (RemoteException e) {
1380 throw e.rethrowFromSystemServer();
1381 }
1382 }
1383
1384 /**
RoboErik4197cb62015-01-21 15:45:32 -08001385 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001387 * Do not use. This method has been deprecated and is now a no-op.
1388 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 *
1390 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001391 * @param state The required solo state: true for solo ON, false for solo
1392 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001393 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001394 * @deprecated Do not use. If you need exclusive audio playback use
1395 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 */
RoboErik4197cb62015-01-21 15:45:32 -08001397 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001399 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 }
1401
1402 /**
1403 * Mute or unmute an audio stream.
1404 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001405 * This method should only be used by applications that replace the
1406 * platform-wide management of audio settings or the main telephony
1407 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001409 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001410 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001411 * <p>
1412 * This method was deprecated in API level 22. Prior to API level 22 this
1413 * method had significantly different behavior and should be used carefully.
1414 * The following applies only to pre-22 platforms:
1415 * <ul>
1416 * <li>The mute command is protected against client process death: if a
1417 * process with an active mute request on a stream dies, this stream will be
1418 * unmuted automatically.</li>
1419 * <li>The mute requests for a given stream are cumulative: the AudioManager
1420 * can receive several mute requests from one or more clients and the stream
1421 * will be unmuted only when the same number of unmute requests are
1422 * received.</li>
1423 * <li>For a better user experience, applications MUST unmute a muted stream
1424 * in onPause() and mute is again in onResume() if appropriate.</li>
1425 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 *
1427 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001428 * @param state The required mute state: true for mute ON, false for mute
1429 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001430 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001431 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1432 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 */
RoboErik4197cb62015-01-21 15:45:32 -08001434 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001436 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1437 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1438 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1439 adjustSuggestedStreamVolume(direction, streamType, 0);
1440 } else {
1441 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 }
1443 }
1444
1445 /**
RoboErik4197cb62015-01-21 15:45:32 -08001446 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001447 *
RoboErik4197cb62015-01-21 15:45:32 -08001448 * @param streamType The stream to get mute state for.
1449 * @return The mute state for the given stream.
1450 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001451 */
1452 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001453 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001454 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001455 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001456 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001457 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001458 }
1459 }
1460
1461 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001462 * get master mute state.
1463 *
1464 * @hide
1465 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001466 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001467 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001468 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001469 try {
1470 return service.isMasterMute();
1471 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001472 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001473 }
1474 }
1475
1476 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001477 * forces the stream controlled by hard volume keys
1478 * specifying streamType == -1 releases control to the
1479 * logic.
1480 *
1481 * @hide
1482 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001483 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001484 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001485 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001486 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001487 try {
1488 service.forceVolumeControlStream(streamType, mICallBack);
1489 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001490 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001491 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001492 }
1493
1494 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 * Returns whether a particular type should vibrate according to user
1496 * settings and the current ringer mode.
1497 * <p>
1498 * This shouldn't be needed by most clients that use notifications to
1499 * vibrate. The notification manager will not vibrate if the policy doesn't
1500 * allow it, so the client should always set a vibrate pattern and let the
1501 * notification manager control whether or not to actually vibrate.
1502 *
1503 * @param vibrateType The type of vibrate. One of
1504 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1505 * {@link #VIBRATE_TYPE_RINGER}.
1506 * @return Whether the type should vibrate at the instant this method is
1507 * called.
1508 * @see #setVibrateSetting(int, int)
1509 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001510 * @deprecated Applications should maintain their own vibrate policy based on
1511 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 */
1513 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001514 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 try {
1516 return service.shouldVibrate(vibrateType);
1517 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001518 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 }
1520 }
1521
1522 /**
1523 * Returns whether the user's vibrate setting for a vibrate type.
1524 * <p>
1525 * This shouldn't be needed by most clients that want to vibrate, instead
1526 * see {@link #shouldVibrate(int)}.
1527 *
1528 * @param vibrateType The type of vibrate. One of
1529 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1530 * {@link #VIBRATE_TYPE_RINGER}.
1531 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1532 * {@link #VIBRATE_SETTING_OFF}, or
1533 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1534 * @see #setVibrateSetting(int, int)
1535 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001536 * @deprecated Applications should maintain their own vibrate policy based on
1537 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 */
1539 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001540 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 try {
1542 return service.getVibrateSetting(vibrateType);
1543 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001544 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 }
1546 }
1547
1548 /**
1549 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001550 * <p>
1551 * This method should only be used by applications that replace the platform-wide
1552 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 *
1554 * @param vibrateType The type of vibrate. One of
1555 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1556 * {@link #VIBRATE_TYPE_RINGER}.
1557 * @param vibrateSetting The vibrate setting, one of
1558 * {@link #VIBRATE_SETTING_ON},
1559 * {@link #VIBRATE_SETTING_OFF}, or
1560 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1561 * @see #getVibrateSetting(int)
1562 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001563 * @deprecated Applications should maintain their own vibrate policy based on
1564 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 */
1566 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001567 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 try {
1569 service.setVibrateSetting(vibrateType, vibrateSetting);
1570 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001571 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 }
1573 }
1574
1575 /**
1576 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001577 * <p>
1578 * This method should only be used by applications that replace the platform-wide
1579 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 *
1581 * @param on set <var>true</var> to turn on speakerphone;
1582 * <var>false</var> to turn it off
1583 */
1584 public void setSpeakerphoneOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001585 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001586 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001587 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001588 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001589 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
1592
1593 /**
1594 * Checks whether the speakerphone is on or off.
1595 *
1596 * @return true if speakerphone is on, false if it's off
1597 */
1598 public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001599 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001600 try {
1601 return service.isSpeakerphoneOn();
1602 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001603 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 }
1606
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001607 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001608 * 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 -07001609 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001610 *
1611 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1612 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001613 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001614 * <ul>
1615 * <li> for each track independently, see
1616 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1617 * <li> application-wide at runtime, with this method </li>
1618 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1619 * manifest. </li>
1620 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001621 * The most restrictive policy is always applied.
1622 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001623 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001624 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001625 *
1626 * @param capturePolicy one of
1627 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1628 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1629 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001630 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001631 */
1632 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001633 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001634 final IAudioService service = getService();
1635 try {
1636 int result = service.setAllowedCapturePolicy(capturePolicy);
1637 if (result != AudioSystem.AUDIO_STATUS_OK) {
1638 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1639 return;
1640 }
1641 } catch (RemoteException e) {
1642 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001643 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001644 }
1645
Kevin Rocard019f60d2019-04-09 16:25:26 -07001646 /**
1647 * Return the capture policy.
1648 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1649 * the default if it was not called.
1650 */
1651 @AudioAttributes.CapturePolicy
1652 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001653 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1654 try {
1655 result = getService().getAllowedCapturePolicy();
1656 } catch (RemoteException e) {
1657 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1658 }
1659 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001660 }
1661
Eric Laurent3def1ee2010-03-17 23:26:26 -07001662 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001663 // Audio Product Strategy routing
1664
1665 /**
1666 * @hide
1667 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1668 * this audio strategy. Note that the device may not be available at the time the preferred
1669 * device is set, but it will be used once made available.
1670 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1671 * this preference for this strategy.</p>
1672 * @param strategy the audio strategy whose routing will be affected
1673 * @param device the audio device to route to when available
1674 * @return true if the operation was successful, false otherwise
1675 */
1676 @SystemApi
1677 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1678 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001679 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001680 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001681 }
1682
1683 /**
1684 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001685 * Removes the preferred audio device(s) previously set with
1686 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1687 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001688 * @param strategy the audio strategy whose routing will be affected
1689 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1690 * device set for example)
1691 */
1692 @SystemApi
1693 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1694 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1695 Objects.requireNonNull(strategy);
1696 try {
1697 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001698 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001699 return status == AudioSystem.SUCCESS;
1700 } catch (RemoteException e) {
1701 throw e.rethrowFromSystemServer();
1702 }
1703 }
1704
1705 /**
1706 * @hide
1707 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001708 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1709 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1710 * @param strategy the strategy to query
1711 * @return the preferred device for that strategy, if multiple devices are set as preferred
1712 * devices, the first one in the list will be returned. Null will be returned if none was
1713 * ever set or if the strategy is invalid
1714 */
1715 @SystemApi
1716 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1717 @Nullable
1718 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1719 @NonNull AudioProductStrategy strategy) {
1720 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1721 return devices.isEmpty() ? null : devices.get(0);
1722 }
1723
1724 /**
1725 * @hide
1726 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1727 * this audio strategy. Note that the devices may not be available at the time the preferred
1728 * devices is set, but it will be used once made available.
1729 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1730 * this preference for this strategy.</p>
1731 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1732 * devices used simultaneously to output the same audio signal.
1733 * @param strategy the audio strategy whose routing will be affected
1734 * @param devices a non-empty list of the audio devices to route to when available
1735 * @return true if the operation was successful, false otherwise
1736 */
1737 @SystemApi
1738 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1739 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1740 @NonNull List<AudioDeviceAttributes> devices) {
1741 Objects.requireNonNull(strategy);
1742 Objects.requireNonNull(devices);
1743 if (devices.isEmpty()) {
1744 throw new IllegalArgumentException(
1745 "Tried to set preferred devices for strategy with a empty list");
1746 }
1747 for (AudioDeviceAttributes device : devices) {
1748 Objects.requireNonNull(device);
1749 }
1750 try {
1751 final int status =
1752 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1753 return status == AudioSystem.SUCCESS;
1754 } catch (RemoteException e) {
1755 throw e.rethrowFromSystemServer();
1756 }
1757 }
1758
1759 /**
1760 * @hide
1761 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001762 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001763 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001764 * @param strategy the strategy to query
1765 * @return the preferred device for that strategy, or null if none was ever set or if the
1766 * strategy is invalid
1767 */
1768 @SystemApi
1769 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001770 @NonNull
1771 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001772 @NonNull AudioProductStrategy strategy) {
1773 Objects.requireNonNull(strategy);
1774 try {
jiabinf40141d2020-08-07 17:27:48 -07001775 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001776 } catch (RemoteException e) {
1777 throw e.rethrowFromSystemServer();
1778 }
1779 }
1780
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001781 /**
1782 * @hide
1783 * Interface to be notified of changes in the preferred audio device set for a given audio
1784 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001785 * <p>Note that this listener will only be invoked whenever
1786 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001787 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001788 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1789 * preferred device. It will not be invoked directly after registration with
1790 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1791 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001792 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001793 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1794 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001795 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001796 */
1797 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001798 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001799 public interface OnPreferredDeviceForStrategyChangedListener {
1800 /**
1801 * Called on the listener to indicate that the preferred audio device for the given
1802 * strategy has changed.
1803 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1804 * @param device <code>null</code> if the preferred device was removed, or the newly set
1805 * preferred audio device
1806 */
1807 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001808 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001809 }
1810
1811 /**
1812 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001813 * Interface to be notified of changes in the preferred audio devices set for a given audio
1814 * strategy.
1815 * <p>Note that this listener will only be invoked whenever
1816 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1817 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1818 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1819 * preferred device(s). It will not be invoked directly after registration with
1820 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1821 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1822 * to indicate which strategies had preferred devices at the time of registration.</p>
1823 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1824 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1825 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1826 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
1827 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1828 */
1829 @SystemApi
1830 public interface OnPreferredDevicesForStrategyChangedListener {
1831 /**
1832 * Called on the listener to indicate that the preferred audio devices for the given
1833 * strategy has changed.
1834 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1835 * @param devices a list of newly set preferred audio devices
1836 */
1837 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1838 @NonNull List<AudioDeviceAttributes> devices);
1839 }
1840
1841 /**
1842 * @hide
1843 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1844 * @param executor
1845 * @param listener
1846 * @throws SecurityException if the caller doesn't hold the required permission
1847 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1848 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1849 */
1850 @SystemApi
1851 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1852 @Deprecated
1853 public void addOnPreferredDeviceForStrategyChangedListener(
1854 @NonNull @CallbackExecutor Executor executor,
1855 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
1856 throws SecurityException {
1857 // No-op, the method is deprecated.
1858 }
1859
1860 /**
1861 * @hide
1862 * Removes a previously added listener of changes to the strategy-preferred audio device.
1863 * @param listener
1864 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
1865 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1866 */
1867 @SystemApi
1868 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1869 @Deprecated
1870 public void removeOnPreferredDeviceForStrategyChangedListener(
1871 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
1872 // No-op, the method is deprecated.
1873 }
1874
1875 /**
1876 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001877 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1878 * @param executor
1879 * @param listener
1880 * @throws SecurityException if the caller doesn't hold the required permission
1881 */
1882 @SystemApi
1883 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001884 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001885 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07001886 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001887 throws SecurityException {
1888 Objects.requireNonNull(executor);
1889 Objects.requireNonNull(listener);
1890 synchronized (mPrefDevListenerLock) {
1891 if (hasPrefDevListener(listener)) {
1892 throw new IllegalArgumentException(
jiabinf40141d2020-08-07 17:27:48 -07001893 "attempt to call addOnPreferredDevicesForStrategyChangedListener() "
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001894 + "on a previously registered listener");
1895 }
1896 // lazy initialization of the list of strategy-preferred device listener
1897 if (mPrefDevListeners == null) {
1898 mPrefDevListeners = new ArrayList<>();
1899 }
1900 final int oldCbCount = mPrefDevListeners.size();
1901 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor));
1902 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) {
1903 // register binder for callbacks
1904 if (mPrefDevDispatcherStub == null) {
jiabinf40141d2020-08-07 17:27:48 -07001905 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001906 }
1907 try {
jiabinf40141d2020-08-07 17:27:48 -07001908 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001909 } catch (RemoteException e) {
1910 throw e.rethrowFromSystemServer();
1911 }
1912 }
1913 }
1914 }
1915
1916 /**
1917 * @hide
1918 * Removes a previously added listener of changes to the strategy-preferred audio device.
1919 * @param listener
1920 */
1921 @SystemApi
1922 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001923 public void removeOnPreferredDevicesForStrategyChangedListener(
1924 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001925 Objects.requireNonNull(listener);
1926 synchronized (mPrefDevListenerLock) {
1927 if (!removePrefDevListener(listener)) {
1928 throw new IllegalArgumentException(
1929 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() "
1930 + "on an unregistered listener");
1931 }
1932 if (mPrefDevListeners.size() == 0) {
1933 // unregister binder for callbacks
1934 try {
jiabinf40141d2020-08-07 17:27:48 -07001935 getService().unregisterStrategyPreferredDevicesDispatcher(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001936 mPrefDevDispatcherStub);
1937 } catch (RemoteException e) {
1938 throw e.rethrowFromSystemServer();
1939 } finally {
1940 mPrefDevDispatcherStub = null;
1941 mPrefDevListeners = null;
1942 }
1943 }
1944 }
1945 }
1946
1947
1948 private final Object mPrefDevListenerLock = new Object();
1949 /**
1950 * List of listeners for preferred device for strategy and their associated Executor.
1951 * List is lazy-initialized on first registration
1952 */
1953 @GuardedBy("mPrefDevListenerLock")
1954 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners;
1955
1956 private static class PrefDevListenerInfo {
jiabinf40141d2020-08-07 17:27:48 -07001957 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001958 final @NonNull Executor mExecutor;
jiabinf40141d2020-08-07 17:27:48 -07001959 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001960 mListener = listener;
1961 mExecutor = exe;
1962 }
1963 }
1964
1965 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07001966 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001967
jiabinf40141d2020-08-07 17:27:48 -07001968 private final class StrategyPreferredDevicesDispatcherStub
1969 extends IStrategyPreferredDevicesDispatcher.Stub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001970
1971 @Override
jiabinf40141d2020-08-07 17:27:48 -07001972 public void dispatchPrefDevicesChanged(int strategyId,
1973 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001974 // make a shallow copy of listeners so callback is not executed under lock
1975 final ArrayList<PrefDevListenerInfo> prefDevListeners;
1976 synchronized (mPrefDevListenerLock) {
1977 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) {
1978 return;
1979 }
1980 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone();
1981 }
1982 final AudioProductStrategy strategy =
1983 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
1984 final long ident = Binder.clearCallingIdentity();
1985 try {
1986 for (PrefDevListenerInfo info : prefDevListeners) {
1987 info.mExecutor.execute(() ->
jiabinf40141d2020-08-07 17:27:48 -07001988 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices));
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001989 }
1990 } finally {
1991 Binder.restoreCallingIdentity(ident);
1992 }
1993 }
1994 }
1995
1996 @GuardedBy("mPrefDevListenerLock")
1997 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo(
jiabinf40141d2020-08-07 17:27:48 -07001998 OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001999 if (mPrefDevListeners == null) {
2000 return null;
2001 }
2002 for (PrefDevListenerInfo info : mPrefDevListeners) {
2003 if (info.mListener == listener) {
2004 return info;
2005 }
2006 }
2007 return null;
2008 }
2009
2010 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002011 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002012 return getPrefDevListenerInfo(listener) != null;
2013 }
2014
2015 @GuardedBy("mPrefDevListenerLock")
2016 /**
2017 * @return true if the listener was removed from the list
2018 */
jiabinf40141d2020-08-07 17:27:48 -07002019 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002020 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener);
2021 if (infoToRemove != null) {
2022 mPrefDevListeners.remove(infoToRemove);
2023 return true;
2024 }
2025 return false;
2026 }
2027
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002028 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002029 // Audio Capture Preset routing
2030
2031 /**
2032 * @hide
2033 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2034 * this capture preset. Note that the device may not be available at the time the preferred
2035 * device is set, but it will be used once made available.
2036 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2037 * for this capture preset.</p>
2038 * @param capturePreset the audio capture preset whose routing will be affected
2039 * @param device the audio device to route to when available
2040 * @return true if the operation was successful, false otherwise
2041 */
2042 @SystemApi
2043 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002044 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002045 @NonNull AudioDeviceAttributes device) {
2046 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2047 }
2048
2049 /**
2050 * @hide
2051 * Remove all the preferred audio devices previously set
2052 * @param capturePreset the audio capture preset whose routing will be affected
2053 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2054 * device set for example)
2055 */
2056 @SystemApi
2057 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002058 public boolean clearPreferredDevicesForCapturePreset(
2059 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002060 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2061 return false;
2062 }
2063 try {
2064 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2065 return status == AudioSystem.SUCCESS;
2066 } catch (RemoteException e) {
2067 throw e.rethrowFromSystemServer();
2068 }
2069 }
2070
2071 /**
2072 * @hide
2073 * Return the preferred devices for an audio capture preset, previously set with
2074 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2075 * @param capturePreset the capture preset to query
2076 * @return a list that contains preferred devices for that capture preset.
2077 */
2078 @NonNull
2079 @SystemApi
2080 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002081 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2082 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002083 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2084 return new ArrayList<AudioDeviceAttributes>();
2085 }
2086 try {
2087 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2088 } catch (RemoteException e) {
2089 throw e.rethrowFromSystemServer();
2090 }
2091 }
2092
2093 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002094 @MediaRecorder.SystemSource int capturePreset,
2095 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002096 Objects.requireNonNull(devices);
2097 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2098 return false;
2099 }
2100 if (devices.size() != 1) {
2101 throw new IllegalArgumentException(
2102 "Only support setting one preferred devices for capture preset");
2103 }
2104 for (AudioDeviceAttributes device : devices) {
2105 Objects.requireNonNull(device);
2106 }
2107 try {
2108 final int status =
2109 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2110 return status == AudioSystem.SUCCESS;
2111 } catch (RemoteException e) {
2112 throw e.rethrowFromSystemServer();
2113 }
2114 }
2115
2116 /**
2117 * @hide
2118 * Interface to be notified of changes in the preferred audio devices set for a given capture
2119 * preset.
2120 * <p>Note that this listener will only be invoked whenever
2121 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2122 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2123 * preferred device. It will not be invoked directly after registration with
2124 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2125 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2126 * to indicate which strategies had preferred devices at the time of registration.</p>
2127 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2128 * @see #clearPreferredDevicesForCapturePreset(int)
2129 * @see #getPreferredDevicesForCapturePreset(int)
2130 */
2131 @SystemApi
2132 public interface OnPreferredDevicesForCapturePresetChangedListener {
2133 /**
2134 * Called on the listener to indicate that the preferred audio devices for the given
2135 * capture preset has changed.
2136 * @param capturePreset the capture preset whose preferred device changed
2137 * @param devices a list of newly set preferred audio devices
2138 */
2139 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002140 @MediaRecorder.SystemSource int capturePreset,
2141 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002142 }
2143
2144 /**
2145 * @hide
2146 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2147 * @param executor
2148 * @param listener
2149 * @throws SecurityException if the caller doesn't hold the required permission
2150 */
2151 @SystemApi
2152 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2153 public void addOnPreferredDevicesForCapturePresetChangedListener(
2154 @NonNull @CallbackExecutor Executor executor,
2155 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2156 throws SecurityException {
2157 Objects.requireNonNull(executor);
2158 Objects.requireNonNull(listener);
2159 int status = addOnDevRoleForCapturePresetChangedListener(
2160 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2161 if (status == AudioSystem.ERROR) {
2162 // This must not happen
2163 throw new RuntimeException("Unknown error happened");
2164 }
2165 if (status == AudioSystem.BAD_VALUE) {
2166 throw new IllegalArgumentException(
2167 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2168 + "on a previously registered listener");
2169 }
2170 }
2171
2172 /**
2173 * @hide
2174 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2175 * @param listener
2176 */
2177 @SystemApi
2178 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2179 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2180 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2181 Objects.requireNonNull(listener);
2182 int status = removeOnDevRoleForCapturePresetChangedListener(
2183 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2184 if (status == AudioSystem.ERROR) {
2185 // This must not happen
2186 throw new RuntimeException("Unknown error happened");
2187 }
2188 if (status == AudioSystem.BAD_VALUE) {
2189 throw new IllegalArgumentException(
2190 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2191 + "on an unregistered listener");
2192 }
2193 }
2194
2195 private <T> int addOnDevRoleForCapturePresetChangedListener(
2196 @NonNull @CallbackExecutor Executor executor,
2197 @NonNull T listener, int deviceRole) {
2198 Objects.requireNonNull(executor);
2199 Objects.requireNonNull(listener);
2200 DevRoleListeners<T> devRoleListeners =
2201 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2202 if (devRoleListeners == null) {
2203 return AudioSystem.ERROR;
2204 }
2205 synchronized (devRoleListeners.mDevRoleListenersLock) {
2206 if (devRoleListeners.hasDevRoleListener(listener)) {
2207 return AudioSystem.BAD_VALUE;
2208 }
2209 // lazy initialization of the list of device role listener
2210 if (devRoleListeners.mListenerInfos == null) {
2211 devRoleListeners.mListenerInfos = new ArrayList<>();
2212 }
2213 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2214 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2215 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2216 // register binder for callbacks
2217 synchronized (mDevRoleForCapturePresetListenersLock) {
2218 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2219 mDeviceRoleListenersStatus |= (1 << deviceRole);
2220 if (deviceRoleListenerStatus != 0) {
2221 // There are already device role changed listeners active.
2222 return AudioSystem.SUCCESS;
2223 }
2224 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2225 mDevicesRoleForCapturePresetDispatcherStub =
2226 new CapturePresetDevicesRoleDispatcherStub();
2227 }
2228 try {
2229 getService().registerCapturePresetDevicesRoleDispatcher(
2230 mDevicesRoleForCapturePresetDispatcherStub);
2231 } catch (RemoteException e) {
2232 throw e.rethrowFromSystemServer();
2233 }
2234 }
2235 }
2236 }
2237 return AudioSystem.SUCCESS;
2238 }
2239
2240 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2241 @NonNull T listener, int deviceRole) {
2242 Objects.requireNonNull(listener);
2243 DevRoleListeners<T> devRoleListeners =
2244 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2245 if (devRoleListeners == null) {
2246 return AudioSystem.ERROR;
2247 }
2248 synchronized (devRoleListeners.mDevRoleListenersLock) {
2249 if (!devRoleListeners.removeDevRoleListener(listener)) {
2250 return AudioSystem.BAD_VALUE;
2251 }
2252 if (devRoleListeners.mListenerInfos.size() == 0) {
2253 // unregister binder for callbacks
2254 synchronized (mDevRoleForCapturePresetListenersLock) {
2255 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2256 if (mDeviceRoleListenersStatus != 0) {
2257 // There are some other device role changed listeners active.
2258 return AudioSystem.SUCCESS;
2259 }
2260 try {
2261 getService().unregisterCapturePresetDevicesRoleDispatcher(
2262 mDevicesRoleForCapturePresetDispatcherStub);
2263 } catch (RemoteException e) {
2264 throw e.rethrowFromSystemServer();
2265 }
2266 }
2267 }
2268 }
2269 return AudioSystem.SUCCESS;
2270 }
2271
2272 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
2273 put(AudioSystem.DEVICE_ROLE_PREFERRED,
2274 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
2275 }};
2276
2277 private class DevRoleListenerInfo<T> {
2278 final @NonNull Executor mExecutor;
2279 final @NonNull T mListener;
2280 DevRoleListenerInfo(Executor executor, T listener) {
2281 mExecutor = executor;
2282 mListener = listener;
2283 }
2284 }
2285
2286 private class DevRoleListeners<T> {
2287 private final Object mDevRoleListenersLock = new Object();
2288 @GuardedBy("mDevRoleListenersLock")
2289 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2290
2291 @GuardedBy("mDevRoleListenersLock")
2292 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2293 if (mListenerInfos == null) {
2294 return null;
2295 }
2296 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2297 if (listenerInfo.mListener == listener) {
2298 return listenerInfo;
2299 }
2300 }
2301 return null;
2302 }
2303
2304 @GuardedBy("mDevRoleListenersLock")
2305 private boolean hasDevRoleListener(T listener) {
2306 return getDevRoleListenerInfo(listener) != null;
2307 }
2308
2309 @GuardedBy("mDevRoleListenersLock")
2310 private boolean removeDevRoleListener(T listener) {
2311 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2312 if (infoToRemove != null) {
2313 mListenerInfos.remove(infoToRemove);
2314 return true;
2315 }
2316 return false;
2317 }
2318 }
2319
2320 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2321 /**
2322 * Record if there is a listener added for device role change. If there is a listener added for
2323 * a specified device role change, the bit at position `1 << device_role` is set.
2324 */
2325 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2326 private int mDeviceRoleListenersStatus = 0;
2327 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2328 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2329
2330 private final class CapturePresetDevicesRoleDispatcherStub
2331 extends ICapturePresetDevicesRoleDispatcher.Stub {
2332
2333 @Override
2334 public void dispatchDevicesRoleChanged(
2335 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2336 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2337 if (listenersObj == null) {
2338 return;
2339 }
2340 switch (role) {
2341 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2342 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2343 listeners =
2344 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2345 listenersObj;
2346 final ArrayList<DevRoleListenerInfo<
2347 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2348 synchronized (listeners.mDevRoleListenersLock) {
2349 if (listeners.mListenerInfos.isEmpty()) {
2350 return;
2351 }
2352 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2353 OnPreferredDevicesForCapturePresetChangedListener>>)
2354 listeners.mListenerInfos.clone();
2355 }
2356 final long ident = Binder.clearCallingIdentity();
2357 try {
2358 for (DevRoleListenerInfo<
2359 OnPreferredDevicesForCapturePresetChangedListener> info :
2360 prefDevListeners) {
2361 info.mExecutor.execute(() ->
2362 info.mListener.onPreferredDevicesForCapturePresetChanged(
2363 capturePreset, devices));
2364 }
2365 } finally {
2366 Binder.restoreCallingIdentity(ident);
2367 }
2368 } break;
2369 default:
2370 break;
2371 }
2372 }
2373 }
2374
2375 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002376 // Offload query
2377 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002378 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002379 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2380 * is not competing with other software resources. In general, it is supported by dedicated
2381 * hardware, such as audio DSPs.
2382 * <p>Note that this query only provides information about the support of an audio format,
2383 * it does not indicate whether the resources necessary for the offloaded playback are
2384 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002385 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002386 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002387 * @return true if the given audio format can be offloaded.
2388 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002389 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2390 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002391 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002392 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002393 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002394 if (attributes == null) {
2395 throw new NullPointerException("Illegal null AudioAttributes");
2396 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002397 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2398 }
2399
2400 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2401 offload playback not supported */
2402 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2403 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2404 offload playback supported */
2405 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2406 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2407 offload playback supported with gapless transitions */
2408 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2409 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2410
2411 /** @hide */
2412 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2413 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2414 PLAYBACK_OFFLOAD_SUPPORTED,
2415 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2416 )
2417 @Retention(RetentionPolicy.SOURCE)
2418 public @interface AudioOffloadMode {}
2419
2420 /**
2421 * Returns whether offloaded playback of an audio format is supported on the device or not and
2422 * when supported whether gapless transitions are possible or not.
2423 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2424 * is not competing with other software resources. In general, it is supported by dedicated
2425 * hardware, such as audio DSPs.
2426 * <p>Note that this query only provides information about the support of an audio format,
2427 * it does not indicate whether the resources necessary for the offloaded playback are
2428 * available at that instant.
2429 * @param format the audio format (codec, sample rate, channels) being checked.
2430 * @param attributes the {@link AudioAttributes} to be used for playback
2431 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2432 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2433 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2434 * also supported.
2435 */
2436 @AudioOffloadMode
2437 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2438 @NonNull AudioAttributes attributes) {
2439 if (format == null) {
2440 throw new NullPointerException("Illegal null AudioFormat");
2441 }
2442 if (attributes == null) {
2443 throw new NullPointerException("Illegal null AudioAttributes");
2444 }
2445 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002446 }
2447
2448 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002449 // Immersive audio
2450
2451 /**
2452 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002453 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002454 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2455 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002456 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002457 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002458 return new Spatializer(this);
2459 }
2460
2461 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002462 // Bluetooth SCO control
2463 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002464 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002465 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002466 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2467 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2468 *
2469 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002470 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002471 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002472 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002473 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2474 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2475 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002476
2477 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002478 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002479 * connection state has been updated.
2480 * <p>This intent has two extras:
2481 * <ul>
2482 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2483 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2484 * </ul>
2485 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2486 * <ul>
2487 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2488 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2489 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2490 * </ul>
2491 * @see #startBluetoothSco()
2492 */
2493 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2494 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2495 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2496
Eric Laurent3def1ee2010-03-17 23:26:26 -07002497 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002498 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2499 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002500 */
2501 public static final String EXTRA_SCO_AUDIO_STATE =
2502 "android.media.extra.SCO_AUDIO_STATE";
2503
2504 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002505 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2506 * bluetooth SCO connection state.
2507 */
2508 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2509 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2510
2511 /**
2512 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2513 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002514 */
2515 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2516 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002517 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2518 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002519 */
2520 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2521 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002522 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2523 * indicating that the SCO audio channel is being established
2524 */
2525 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2526 /**
2527 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002528 * there was an error trying to obtain the state
2529 */
2530 public static final int SCO_AUDIO_STATE_ERROR = -1;
2531
2532
2533 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002534 * Indicates if current platform supports use of SCO for off call use cases.
2535 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002536 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002537 * feature.
2538 * @return true if bluetooth SCO can be used for audio when not in call
2539 * false otherwise
2540 * @see #startBluetoothSco()
2541 */
2542 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002543 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002544 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2545 }
2546
2547 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002548 * Start bluetooth SCO audio connection.
2549 * <p>Requires Permission:
2550 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2551 * <p>This method can be used by applications wanting to send and received audio
2552 * to/from a bluetooth SCO headset while the phone is not in call.
2553 * <p>As the SCO connection establishment can take several seconds,
2554 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002555 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002556 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002557 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2558 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2559 * registration. If the state is already CONNECTED, no state change will be received via the
2560 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2561 * so that the connection stays active in case the current initiator stops the connection.
2562 * <p>Unless the connection is already active as described above, the state will always
2563 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2564 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2565 * <p>When finished with the SCO connection or if the establishment fails, the application must
2566 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002567 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2568 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002569 * <ul>
2570 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2571 * <li> the format must be mono </li>
2572 * <li> the sampling must be 16kHz or 8kHz </li>
2573 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002574 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002575 * <ul>
2576 * <li> the format must be mono </li>
2577 * <li> the sampling must be 8kHz </li>
2578 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002579 * <p>Note that the phone application always has the priority on the usage of the SCO
2580 * connection for telephony. If this method is called while the phone is in call
2581 * it will be ignored. Similarly, if a call is received or sent while an application
2582 * is using the SCO connection, the connection will be lost for the application and NOT
2583 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002584 * <p>NOTE: up to and including API version
2585 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2586 * voice call to the bluetooth headset.
2587 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2588 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002589 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002590 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurent3def1ee2010-03-17 23:26:26 -07002591 */
2592 public void startBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002593 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002594 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002595 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002596 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002597 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002598 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002599 }
2600 }
2601
2602 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002603 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002604 * Start bluetooth SCO audio connection in virtual call mode.
2605 * <p>Requires Permission:
2606 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2607 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2608 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2609 * virtual call mode.
2610 * Applications using voice input for search or commands should first try raw audio connection
2611 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2612 * failure.
2613 * @see #startBluetoothSco()
2614 * @see #stopBluetoothSco()
2615 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2616 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002617 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002618 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002619 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002620 try {
2621 service.startBluetoothScoVirtualCall(mICallBack);
2622 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002623 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002624 }
2625 }
2626
2627 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002628 * Stop bluetooth SCO audio connection.
2629 * <p>Requires Permission:
2630 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2631 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002632 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2633 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002634 * @see #startBluetoothSco()
2635 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002636 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002637 public void stopBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002638 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002639 try {
2640 service.stopBluetoothSco(mICallBack);
2641 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002642 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002643 }
2644 }
2645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002646 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002647 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002648 * <p>
2649 * This method should only be used by applications that replace the platform-wide
2650 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002651 *
Eric Laurenta553c252009-07-17 12:17:14 -07002652 * @param on set <var>true</var> to use bluetooth SCO for communications;
2653 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 */
2655 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002656 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002657 try {
2658 service.setBluetoothScoOn(on);
2659 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002660 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 }
2663
2664 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002665 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002666 *
Eric Laurenta553c252009-07-17 12:17:14 -07002667 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002668 * false if otherwise
2669 */
2670 public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002671 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002672 try {
2673 return service.isBluetoothScoOn();
2674 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002675 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002676 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677 }
2678
2679 /**
Eric Laurent242b3382012-06-15 11:48:50 -07002680 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2681 * headset; <var>false</var> disable A2DP audio
Eric Laurenta553c252009-07-17 12:17:14 -07002682 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 */
Eric Laurenta553c252009-07-17 12:17:14 -07002684 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
2686
2687 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002688 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002689 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002690 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002691 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002692 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002693 */
2694 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002695 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002696 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2697 return true;
2698 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2699 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2700 return true;
2701 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2702 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002703 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002704 }
Eric Laurent9656df22016-04-20 16:42:28 -07002705 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002706 }
2707
2708 /**
2709 * Sets audio routing to the wired headset on or off.
2710 *
2711 * @param on set <var>true</var> to route audio to/from wired
2712 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002713 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 */
Eric Laurenta553c252009-07-17 12:17:14 -07002715 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002716 }
2717
2718 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002719 * Checks whether a wired headset is connected or not.
2720 * <p>This is not a valid indication that audio playback is
2721 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002723 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002725 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 */
2727 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002728 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002729 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002730 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002731 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2732 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2733 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002734 return false;
2735 } else {
2736 return true;
2737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 }
2739
2740 /**
2741 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002742 * <p>
2743 * This method should only be used by applications that replace the platform-wide
2744 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002745 *
2746 * @param on set <var>true</var> to mute the microphone;
2747 * <var>false</var> to turn mute off
2748 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002749 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002750 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002751 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002752 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002753 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002754 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002755 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002756 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 }
2758
2759 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002760 * @hide
2761 * Sets the microphone from switch mute on or off.
2762 * <p>
2763 * This method should only be used by InputManager to notify
2764 * Audio Subsystem about Microphone Mute switch state.
2765 *
2766 * @param on set <var>true</var> to mute the microphone;
2767 * <var>false</var> to turn mute off
2768 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002769 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002770 public void setMicrophoneMuteFromSwitch(boolean on) {
2771 final IAudioService service = getService();
2772 try {
2773 service.setMicrophoneMuteFromSwitch(on);
2774 } catch (RemoteException e) {
2775 throw e.rethrowFromSystemServer();
2776 }
2777 }
2778
2779 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002780 * Checks whether the microphone mute is on or off.
2781 *
2782 * @return true if microphone is muted, false if it's not
2783 */
2784 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002785 final IAudioService service = getService();
2786 try {
2787 return service.isMicrophoneMuted();
2788 } catch (RemoteException e) {
2789 throw e.rethrowFromSystemServer();
2790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002791 }
2792
2793 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002794 * Broadcast Action: microphone muting state changed.
2795 *
2796 * You <em>cannot</em> receive this through components declared
2797 * in manifests, only by explicitly registering for it with
2798 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2799 * Context.registerReceiver()}.
2800 *
2801 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2802 * microphone is muted.
2803 */
2804 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2805 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2806 "android.media.action.MICROPHONE_MUTE_CHANGED";
2807
2808 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07002809 * Broadcast Action: speakerphone state changed.
2810 *
2811 * You <em>cannot</em> receive this through components declared
2812 * in manifests, only by explicitly registering for it with
2813 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2814 * Context.registerReceiver()}.
2815 *
2816 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2817 * speakerphone functionality is enabled or not.
2818 */
2819 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2820 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2821 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2822
2823 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002825 * <p>
2826 * The audio mode encompasses audio routing AND the behavior of
2827 * the telephony layer. Therefore this method should only be used by applications that
2828 * replace the platform-wide management of audio settings or the main telephony application.
2829 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2830 * application when it places a phone call, as it will cause signals from the radio layer
2831 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002832 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002833 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002834 * Informs the HAL about the current audio state so that
2835 * it can route the audio appropriately.
2836 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002837 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002838 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002839 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07002840 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002841 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002842 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 }
2844 }
2845
2846 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01002847 * This change id controls use of audio modes for call audio redirection.
2848 * @hide
2849 */
2850 @ChangeId
2851 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
2852 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
2853
2854 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002855 * Returns the current audio mode.
2856 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002857 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002858 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002859 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002861 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002863 int mode = service.getMode();
2864 int sdk;
2865 try {
2866 sdk = getContext().getApplicationInfo().targetSdkVersion;
2867 } catch (NullPointerException e) {
2868 // some tests don't have a Context
2869 sdk = Build.VERSION.SDK_INT;
2870 }
2871 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
2872 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01002873 } else if (mode == MODE_CALL_REDIRECT
2874 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
2875 mode = MODE_IN_CALL;
2876 } else if (mode == MODE_COMMUNICATION_REDIRECT
2877 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
2878 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002879 }
2880 return mode;
2881 } catch (RemoteException e) {
2882 throw e.rethrowFromSystemServer();
2883 }
2884 }
2885
2886 /**
Nate Myren08635fe2021-04-20 12:04:39 -07002887 * Interface definition of a callback that is notified when the audio mode changes
2888 */
2889 public interface OnModeChangedListener {
2890 /**
2891 * Called on the listener to indicate that the audio mode has changed
2892 *
2893 * @param mode The current audio mode
2894 */
2895 void onModeChanged(@AudioMode int mode);
2896 }
2897
2898 private final Object mModeListenerLock = new Object();
2899 /**
2900 * List of listeners for audio mode and their associated Executor.
2901 * List is lazy-initialized on first registration
2902 */
2903 @GuardedBy("mModeListenerLock")
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002904 private @Nullable ArrayList<ListenerInfo<OnModeChangedListener>> mModeListeners;
Nate Myren08635fe2021-04-20 12:04:39 -07002905
2906 @GuardedBy("mModeListenerLock")
2907 private ModeDispatcherStub mModeDispatcherStub;
2908
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002909 private final class ModeDispatcherStub extends IAudioModeDispatcher.Stub {
2910
2911 public void register(boolean register) {
2912 try {
2913 if (register) {
2914 getService().registerModeDispatcher(this);
2915 } else {
2916 getService().unregisterModeDispatcher(this);
2917 }
2918 } catch (RemoteException e) {
2919 e.rethrowFromSystemServer();
2920 }
2921 }
Nate Myren08635fe2021-04-20 12:04:39 -07002922
2923 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002924 @SuppressLint("GuardedBy") // lock applied inside callListeners method
Nate Myren08635fe2021-04-20 12:04:39 -07002925 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002926 CallbackUtil.callListeners(mModeListeners, mModeListenerLock,
2927 (listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07002928 }
2929 }
2930
Nate Myren08635fe2021-04-20 12:04:39 -07002931 /**
2932 * Adds a listener to be notified of changes to the audio mode.
2933 * See {@link #getMode()}
2934 * @param executor
2935 * @param listener
2936 */
2937 public void addOnModeChangedListener(
2938 @NonNull @CallbackExecutor Executor executor,
2939 @NonNull OnModeChangedListener listener) {
Nate Myren08635fe2021-04-20 12:04:39 -07002940 synchronized (mModeListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002941 final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
2942 CallbackUtil.addListener("addOnModeChangedListener",
2943 executor, listener, mModeListeners, mModeDispatcherStub,
2944 () -> new ModeDispatcherStub(),
2945 stub -> stub.register(true));
2946 mModeListeners = res.first;
2947 mModeDispatcherStub = res.second;
Nate Myren08635fe2021-04-20 12:04:39 -07002948 }
2949 }
2950
2951 /**
2952 * Removes a previously added listener for changes to audio mode.
2953 * See {@link #getMode()}
2954 * @param listener
2955 */
2956 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Nate Myren08635fe2021-04-20 12:04:39 -07002957 synchronized (mModeListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002958 final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
2959 CallbackUtil.removeListener("removeOnModeChangedListener",
2960 listener, mModeListeners, mModeDispatcherStub,
2961 stub -> stub.register(false));
2962 mModeListeners = res.first;
2963 mModeDispatcherStub = res.second;
Nate Myren08635fe2021-04-20 12:04:39 -07002964 }
2965 }
2966
2967 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002968 * Indicates if the platform supports a special call screening and call monitoring mode.
2969 * <p>
2970 * When this mode is supported, it is possible to perform call screening and monitoring
2971 * functions while other use cases like music or movie playback are active.
2972 * <p>
2973 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
2974 * call screening mode.
2975 * <p>
2976 * If call screening mode is not supported, setting mode to
2977 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
2978 * {@link #getMode()}.
2979 * @return true if call screening mode is supported, false otherwise.
2980 */
2981 public boolean isCallScreeningModeSupported() {
2982 final IAudioService service = getService();
2983 try {
2984 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002986 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987 }
2988 }
2989
2990 /* modes for setMode/getMode/setRoute/getRoute */
2991 /**
2992 * Audio harware modes.
2993 */
2994 /**
2995 * Invalid audio mode.
2996 */
2997 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
2998 /**
2999 * Current audio mode. Used to apply audio routing to current mode.
3000 */
3001 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3002 /**
3003 * Normal audio mode: not ringing and no call established.
3004 */
3005 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3006 /**
3007 * Ringing audio mode. An incoming is being signaled.
3008 */
3009 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3010 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003011 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003012 */
3013 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003014 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003015 * In communication audio mode. An audio/video chat or VoIP call is established.
3016 */
3017 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003018 /**
3019 * Call screening in progress. Call is connected and audio is accessible to call
3020 * screening applications but other audio use cases are still possible.
3021 */
3022 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3023
Eric Laurent1c3408f2021-11-09 12:09:54 +01003024 /**
3025 * A telephony call is established and its audio is being redirected to another device.
3026 */
3027 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3028
3029 /**
3030 * n audio/video chat or VoIP call is established and its audio is being redirected to another
3031 * device.
3032 */
3033 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3034
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003035 /** @hide */
3036 @IntDef(flag = false, prefix = "MODE_", value = {
3037 MODE_NORMAL,
3038 MODE_RINGTONE,
3039 MODE_IN_CALL,
3040 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003041 MODE_CALL_SCREENING,
3042 MODE_CALL_REDIRECT,
3043 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003044 )
3045 @Retention(RetentionPolicy.SOURCE)
3046 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047
3048 /* Routing bits for setRouting/getRouting API */
3049 /**
3050 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003051 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3052 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003053 */
Eric Laurenta553c252009-07-17 12:17:14 -07003054 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003056 * Routing audio output to speaker
3057 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3058 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 */
Eric Laurenta553c252009-07-17 12:17:14 -07003060 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 /**
3062 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003063 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3064 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003065 */
3066 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3067 /**
3068 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003069 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3070 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071 */
Eric Laurenta553c252009-07-17 12:17:14 -07003072 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003073 /**
3074 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003075 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3076 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077 */
Eric Laurenta553c252009-07-17 12:17:14 -07003078 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 /**
3080 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003081 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3082 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003083 */
Eric Laurenta553c252009-07-17 12:17:14 -07003084 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085 /**
3086 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003087 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3088 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 */
Eric Laurenta553c252009-07-17 12:17:14 -07003090 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091
3092 /**
3093 * Sets the audio routing for a specified mode
3094 *
3095 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3096 * @param routes bit vector of routes requested, created from one or
3097 * more of ROUTE_xxx types. Set bits indicate that route should be on
3098 * @param mask bit vector of routes to change, created from one or more of
3099 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003100 *
3101 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003102 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 */
Eric Laurenta553c252009-07-17 12:17:14 -07003104 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003106 }
3107
3108 /**
3109 * Returns the current audio routing bit vector for a specified mode.
3110 *
3111 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3112 * @return an audio route bit vector that can be compared with ROUTE_xxx
3113 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003114 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3115 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003116 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003117 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003119 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003120 }
3121
3122 /**
3123 * Checks whether any music is active.
3124 *
3125 * @return true if any music tracks are active.
3126 */
3127 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003128 final IAudioService service = getService();
3129 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003130 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003131 } catch (RemoteException e) {
3132 throw e.rethrowFromSystemServer();
3133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003134 }
3135
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003136 /**
3137 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003138 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3139 * display). Note that BT audio sinks are not considered remote devices.
3140 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3141 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003142 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003143 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003144 final IAudioService service = getService();
3145 try {
3146 return service.isMusicActive(true /*remotely*/);
3147 } catch (RemoteException e) {
3148 throw e.rethrowFromSystemServer();
3149 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003150 }
3151
3152 /**
3153 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003154 * Checks whether the current audio focus is exclusive.
3155 * @return true if the top of the audio focus stack requested focus
3156 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3157 */
3158 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003159 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003160 try {
3161 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3162 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003163 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003164 }
3165 }
3166
3167 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003168 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003169 * An audio session identifier is a system wide unique identifier for a set of audio streams
3170 * (one or more mixed together).
3171 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3172 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3173 * session ID will be applied to the mixed audio content of the players that share the same
3174 * audio session.
3175 * <p>This method can for instance be used when creating one of the
3176 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3177 * or to specify a session for a speech synthesis utterance
3178 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003179 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003180 * system failed to generate a new session, a condition in which audio playback or recording
3181 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003182 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003183 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003184 int session = AudioSystem.newAudioSessionId();
3185 if (session > 0) {
3186 return session;
3187 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003188 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003189 return ERROR;
3190 }
3191 }
3192
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003193 /**
3194 * A special audio session ID to indicate that the audio session ID isn't known and the
3195 * framework should generate a new value. This can be used when building a new
3196 * {@link AudioTrack} instance with
3197 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3198 */
3199 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3200
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 /*
3203 * Sets a generic audio configuration parameter. The use of these parameters
3204 * are platform dependant, see libaudio
3205 *
3206 * ** Temporary interface - DO NOT USE
3207 *
3208 * TODO: Replace with a more generic key:value get/set mechanism
3209 *
3210 * param key name of parameter to set. Must not be null.
3211 * param value value of parameter. Must not be null.
3212 */
3213 /**
3214 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003215 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 */
Eric Laurenta553c252009-07-17 12:17:14 -07003217 @Deprecated public void setParameter(String key, String value) {
3218 setParameters(key+"="+value);
3219 }
3220
3221 /**
3222 * Sets a variable number of parameter values to audio hardware.
3223 *
3224 * @param keyValuePairs list of parameters key value pairs in the form:
3225 * key1=value1;key2=value2;...
3226 *
3227 */
3228 public void setParameters(String keyValuePairs) {
3229 AudioSystem.setParameters(keyValuePairs);
3230 }
3231
3232 /**
William Escandeef429b62021-10-15 18:37:40 +02003233 * @hide
3234 */
3235 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3236 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3237 public void setHfpEnabled(boolean enable) {
3238 AudioSystem.setParameters("hfp_enable=" + enable);
3239 }
3240
3241 /**
3242 * @hide
3243 */
3244 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3245 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3246 public void setHfpVolume(int volume) {
3247 AudioSystem.setParameters("hfp_volume=" + volume);
3248 }
3249
3250 /**
3251 * @hide
3252 */
3253 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3254 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3255 public void setHfpSamplingRate(int rate) {
3256 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3257 }
3258
3259 /**
3260 * @hide
3261 */
3262 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3263 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3264 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3265 boolean hasWbsEnabled) {
3266 AudioSystem.setParameters("bt_headset_name=" + name
3267 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3268 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3269 }
3270
3271 /**
3272 * @hide
3273 */
3274 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3275 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3276 public void setA2dpSuspended(boolean enable) {
3277 AudioSystem.setParameters("A2dpSuspended=" + enable);
3278 }
3279
3280 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003281 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003282 *
3283 * @param keys list of parameters
3284 * @return list of parameters key value pairs in the form:
3285 * key1=value1;key2=value2;...
3286 */
3287 public String getParameters(String keys) {
3288 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 }
3290
3291 /* Sound effect identifiers */
3292 /**
3293 * Keyboard and direction pad click sound
3294 * @see #playSoundEffect(int)
3295 */
3296 public static final int FX_KEY_CLICK = 0;
3297 /**
3298 * Focus has moved up
3299 * @see #playSoundEffect(int)
3300 */
3301 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3302 /**
3303 * Focus has moved down
3304 * @see #playSoundEffect(int)
3305 */
3306 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3307 /**
3308 * Focus has moved left
3309 * @see #playSoundEffect(int)
3310 */
3311 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3312 /**
3313 * Focus has moved right
3314 * @see #playSoundEffect(int)
3315 */
3316 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3317 /**
3318 * IME standard keypress sound
3319 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 */
3321 public static final int FX_KEYPRESS_STANDARD = 5;
3322 /**
3323 * IME spacebar keypress sound
3324 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 */
3326 public static final int FX_KEYPRESS_SPACEBAR = 6;
3327 /**
3328 * IME delete keypress sound
3329 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 */
3331 public static final int FX_KEYPRESS_DELETE = 7;
3332 /**
3333 * IME return_keypress sound
3334 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 */
3336 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003337
3338 /**
3339 * Invalid keypress sound
3340 * @see #playSoundEffect(int)
3341 */
3342 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003343
3344 /**
3345 * Back sound
3346 * @see #playSoundEffect(int)
3347 */
3348 public static final int FX_BACK = 10;
3349
3350 /**
3351 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003352 * <p>
3353 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3354 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003355 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3356 * @see #playSoundEffect(int)
3357 */
3358 public static final int FX_HOME = 11;
3359
3360 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003361 * @hide Navigation repeat sound 1
3362 * <p>
3363 * To be played by the framework when a focus navigation is repeatedly triggered
3364 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003365 * This is currently only used on TV devices.
3366 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3367 * @see #playSoundEffect(int)
3368 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003369 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003370
3371 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003372 * @hide Navigation repeat sound 2
3373 * <p>
3374 * To be played by the framework when a focus navigation is repeatedly triggered
3375 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003376 * This is currently only used on TV devices.
3377 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3378 * @see #playSoundEffect(int)
3379 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003380 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003381
3382 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003383 * @hide Navigation repeat sound 3
3384 * <p>
3385 * To be played by the framework when a focus navigation is repeatedly triggered
3386 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003387 * This is currently only used on TV devices.
3388 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3389 * @see #playSoundEffect(int)
3390 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003391 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003392
3393 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003394 * @hide Navigation repeat sound 4
3395 * <p>
3396 * To be played by the framework when a focus navigation is repeatedly triggered
3397 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003398 * This is currently only used on TV devices.
3399 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3400 * @see #playSoundEffect(int)
3401 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003402 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003404 /**
3405 * @hide Number of sound effects
3406 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003407 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003408 public static final int NUM_SOUND_EFFECTS = 16;
3409
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003410 /** @hide */
3411 @IntDef(prefix = { "FX_" }, value = {
3412 FX_KEY_CLICK,
3413 FX_FOCUS_NAVIGATION_UP,
3414 FX_FOCUS_NAVIGATION_DOWN,
3415 FX_FOCUS_NAVIGATION_LEFT,
3416 FX_FOCUS_NAVIGATION_RIGHT,
3417 FX_KEYPRESS_STANDARD,
3418 FX_KEYPRESS_SPACEBAR,
3419 FX_KEYPRESS_DELETE,
3420 FX_KEYPRESS_RETURN,
3421 FX_KEYPRESS_INVALID,
3422 FX_BACK
3423 })
3424 @Retention(RetentionPolicy.SOURCE)
3425 public @interface SystemSoundEffect {}
3426
Philip Junker7f1fdff2020-12-03 16:10:41 +01003427 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003428 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003429 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003430 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003431
3432 /**
3433 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003434 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3435 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003436 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003437 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003438 switch (n) {
3439 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003440 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003441 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003442 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003443 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003444 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003445 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003446 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003447 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003448 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003449 return -1;
3450 }
3451 }
3452
3453 /**
3454 * @hide
3455 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003456 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003457 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003458 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003459 } catch (RemoteException e) {
3460
3461 }
3462 }
3463
3464 /**
3465 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003466 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003467 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003468 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003469 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003470 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003471 } catch (RemoteException e) {
3472 throw e.rethrowFromSystemServer();
3473 }
3474 }
3475
3476 /**
3477 * @hide
3478 * @param enabled
3479 */
3480 public void setHomeSoundEffectEnabled(boolean enabled) {
3481 try {
3482 getService().setHomeSoundEffectEnabled(enabled);
3483 } catch (RemoteException e) {
3484
3485 }
3486 }
3487
3488 /**
3489 * @hide
3490 * @return true if the home sound effect is enabled
3491 */
3492 public boolean isHomeSoundEffectEnabled() {
3493 try {
3494 return getService().isHomeSoundEffectEnabled();
3495 } catch (RemoteException e) {
3496 throw e.rethrowFromSystemServer();
3497 }
3498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499
3500 /**
3501 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003502 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003503 * NOTE: This version uses the UI settings to determine
3504 * whether sounds are heard or not.
3505 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003506 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003507 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003508 }
3509
3510 /**
3511 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003512 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003513 * @param userId The current user to pull sound settings from
3514 * NOTE: This version uses the UI settings to determine
3515 * whether sounds are heard or not.
3516 * @hide
3517 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003518 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003519 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3520 return;
3521 }
3522
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003523 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003525 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003527 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 }
3529 }
3530
3531 /**
3532 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003533 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003534 * @param volume Sound effect volume.
3535 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3536 * 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 -08003537 * NOTE: This version is for applications that have their own
3538 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003540 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3542 return;
3543 }
3544
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003545 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 try {
3547 service.playSoundEffectVolume(effectType, volume);
3548 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003549 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003550 }
3551 }
3552
3553 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 * Load Sound effects.
3555 * This method must be called when sound effects are enabled.
3556 */
3557 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003558 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 try {
3560 service.loadSoundEffects();
3561 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003562 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003563 }
3564 }
3565
3566 /**
3567 * Unload Sound effects.
3568 * This method can be called to free some memory when
3569 * sound effects are disabled.
3570 */
3571 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003572 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 try {
3574 service.unloadSoundEffects();
3575 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003576 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 }
3578 }
3579
Eric Laurent4050c932009-07-08 02:52:14 -07003580 /**
Andy Hung69836952020-03-26 01:00:15 -07003581 * @hide
3582 */
3583 public static String audioFocusToString(int focus) {
3584 switch (focus) {
3585 case AUDIOFOCUS_NONE:
3586 return "AUDIOFOCUS_NONE";
3587 case AUDIOFOCUS_GAIN:
3588 return "AUDIOFOCUS_GAIN";
3589 case AUDIOFOCUS_GAIN_TRANSIENT:
3590 return "AUDIOFOCUS_GAIN_TRANSIENT";
3591 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3592 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3593 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3594 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3595 case AUDIOFOCUS_LOSS:
3596 return "AUDIOFOCUS_LOSS";
3597 case AUDIOFOCUS_LOSS_TRANSIENT:
3598 return "AUDIOFOCUS_LOSS_TRANSIENT";
3599 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3600 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3601 default:
3602 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3603 }
3604 }
3605
3606 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003607 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003608 */
3609 public static final int AUDIOFOCUS_NONE = 0;
3610
3611 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003612 * 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 -07003613 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003614 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003615 */
3616 public static final int AUDIOFOCUS_GAIN = 1;
3617 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003618 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3619 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3620 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003621 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003622 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003623 */
3624 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003625 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003626 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003627 * amount of time, and where it is acceptable for other audio applications to keep playing
3628 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003629 * Examples of temporary changes are the playback of driving directions where playback of music
3630 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003631 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003632 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3633 */
3634 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3635 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003636 * Used to indicate a temporary request of audio focus, anticipated to last a short
3637 * amount of time, during which no other applications, or system components, should play
3638 * anything. Examples of exclusive and transient audio focus requests are voice
3639 * memo recording and speech recognition, during which the system shouldn't play any
3640 * notifications, and media playback should have paused.
3641 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3642 */
3643 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3644 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003645 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003646 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003647 */
3648 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3649 /**
3650 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003651 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003652 */
3653 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3654 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003655 * 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 -07003656 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3657 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003658 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003659 */
3660 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3661 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003662
3663 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003664 * Interface definition for a callback to be invoked when the audio focus of the system is
3665 * updated.
3666 */
3667 public interface OnAudioFocusChangeListener {
3668 /**
3669 * Called on the listener to notify it the audio focus for this listener has been changed.
3670 * The focusChange value indicates whether the focus was gained,
3671 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3672 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003673 * When losing focus, listeners can use the focus change information to decide what
3674 * behavior to adopt when losing focus. A music player could for instance elect to lower
3675 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3676 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003677 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003678 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003679 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003680 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003681 }
3682
3683 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003684 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3685 */
3686 private static class FocusRequestInfo {
3687 @NonNull final AudioFocusRequest mRequest;
3688 @Nullable final Handler mHandler;
3689 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3690 mRequest = afr;
3691 mHandler = handler;
3692 }
3693 }
3694
3695 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003696 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3697 * to actual listener objects.
3698 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003699 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003700 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3701 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003702
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003703 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003704 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003705 }
3706
3707 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003708 * Handler for events (audio focus change, recording config change) coming from the
3709 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003710 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003711 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003712 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003713
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003714 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003715 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003716 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003717 private final static int MSSG_FOCUS_CHANGE = 0;
3718 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003719 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003720
3721 /**
3722 * Helper class to handle the forwarding of audio service events to the appropriate listener
3723 */
3724 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003725 private final Handler mHandler;
3726
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003727 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003728 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003729 if (handler == null) {
3730 if ((looper = Looper.myLooper()) == null) {
3731 looper = Looper.getMainLooper();
3732 }
3733 } else {
3734 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003735 }
3736
3737 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003738 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003739 mHandler = new Handler(looper) {
3740 @Override
3741 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003742 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003743 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003744 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3745 if (fri != null) {
3746 final OnAudioFocusChangeListener listener =
3747 fri.mRequest.getOnAudioFocusChangeListener();
3748 if (listener != null) {
3749 Log.d(TAG, "dispatching onAudioFocusChange("
3750 + msg.arg1 + ") to " + msg.obj);
3751 listener.onAudioFocusChange(msg.arg1);
3752 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003753 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003754 } break;
3755 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08003756 final RecordConfigChangeCallbackData cbData =
3757 (RecordConfigChangeCallbackData) msg.obj;
3758 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07003759 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08003760 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003761 } break;
3762 case MSSG_PLAYBACK_CONFIG_CHANGE: {
3763 final PlaybackConfigChangeCallbackData cbData =
3764 (PlaybackConfigChangeCallbackData) msg.obj;
3765 if (cbData.mCb != null) {
3766 if (DEBUG) {
3767 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3768 }
3769 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3770 }
3771 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003772 default:
3773 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003774 }
3775 }
3776 };
3777 } else {
3778 mHandler = null;
3779 }
3780 }
3781
3782 Handler getHandler() {
3783 return mHandler;
3784 }
3785 }
3786
Glenn Kasten30c918c2011-11-10 17:56:41 -08003787 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003788 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003789 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003790 final FocusRequestInfo fri = findFocusRequestInfo(id);
3791 if (fri != null) {
3792 final OnAudioFocusChangeListener listener =
3793 fri.mRequest.getOnAudioFocusChangeListener();
3794 if (listener != null) {
3795 final Handler h = (fri.mHandler == null) ?
3796 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3797 final Message m = h.obtainMessage(
3798 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3799 id/*obj*/);
3800 h.sendMessage(m);
3801 }
3802 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003803 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003804
3805 @Override
3806 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3807 synchronized (mFocusRequestsLock) {
3808 // TODO use generation counter as the key instead
3809 final BlockingFocusResultReceiver focusReceiver =
3810 mFocusRequestsAwaitingResult.remove(clientId);
3811 if (focusReceiver != null) {
3812 focusReceiver.notifyResult(requestResult);
3813 } else {
3814 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3815 }
3816 }
3817 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003818 };
3819
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003820 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003821 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07003822 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003823 } else {
3824 return new String(this.toString() + l.toString());
3825 }
3826 }
3827
3828 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003829 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003830 * Registers a listener to be called when audio focus changes and keeps track of the associated
3831 * focus request (including Handler to use for the listener).
3832 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003833 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003834 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3835 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3836 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3837 new ServiceEventHandlerDelegate(h).getHandler());
3838 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3839 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003840 }
3841
3842 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003843 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003844 * Causes the specified listener to not be called anymore when focus is gained or lost.
3845 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003846 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003847 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003848 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003849 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003850 }
3851
3852
3853 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003854 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003855 */
3856 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3857 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003858 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003859 */
3860 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003861 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003862 * A focus change request whose granting is delayed: the request was successful, but the
3863 * requester will only be granted audio focus once the condition that prevented immediate
3864 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003865 * See {@link #requestAudioFocus(AudioFocusRequest)} and
3866 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003867 */
3868 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003869
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003870 /** @hide */
3871 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3872 AUDIOFOCUS_REQUEST_FAILED,
3873 AUDIOFOCUS_REQUEST_GRANTED,
3874 AUDIOFOCUS_REQUEST_DELAYED }
3875 )
3876 @Retention(RetentionPolicy.SOURCE)
3877 public @interface FocusRequestResult {}
3878
3879 /**
3880 * @hide
3881 * code returned when a synchronous focus request on the client-side is to be blocked
3882 * until the external audio focus policy decides on the response for the client
3883 */
3884 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
3885
3886 /**
3887 * Timeout duration in ms when waiting on an external focus policy for the result for a
3888 * focus request
3889 */
3890 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
3891
3892 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
3893
3894 private final Object mFocusRequestsLock = new Object();
3895 /**
3896 * Map of all receivers of focus request results, one per unresolved focus request.
3897 * Receivers are added before sending the request to the external focus policy,
3898 * and are removed either after receiving the result, or after the timeout.
3899 * This variable is lazily initialized.
3900 */
3901 @GuardedBy("mFocusRequestsLock")
3902 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
3903
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003904
3905 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003906 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003907 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003908 * @param l the listener to be notified of audio focus changes
3909 * @param streamType the main audio stream type affected by the focus request
3910 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
3911 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003912 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003913 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
3914 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07003915 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
3916 * that benefits from the system not playing disruptive sounds like notifications, for
3917 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003918 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003919 * as the playback of a song or a video.
3920 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08003921 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003922 */
3923 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08003924 PlayerBase.deprecateStreamTypeForPlayback(streamType,
3925 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003926 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003927
3928 try {
3929 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
3930 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
3931 // AUDIOFOCUS_FLAG_DELAY_OK flag
3932 status = requestAudioFocus(l,
3933 new AudioAttributes.Builder()
3934 .setInternalLegacyStreamType(streamType).build(),
3935 durationHint,
3936 0 /* flags, legacy behavior */);
3937 } catch (IllegalArgumentException e) {
3938 Log.e(TAG, "Audio focus request denied due to ", e);
3939 }
3940
3941 return status;
3942 }
3943
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003944 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003945 /**
3946 * @hide
3947 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
3948 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
3949 * the system is in a state where focus cannot change, but be granted focus later when
3950 * this condition ends.
3951 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003952 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003953 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003954 /**
3955 * @hide
3956 * Use this flag when requesting audio focus to indicate that the requester
3957 * will pause its media playback (if applicable) when losing audio focus with
3958 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
3959 * <br>On some platforms, the ducking may be handled without the application being aware of it
3960 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
3961 * content, such as audio book or podcast players, ducking may never be acceptable, and will
3962 * thus always pause. This flag enables them to be declared as such whenever they request focus.
3963 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003964 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003965 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
3966 /**
3967 * @hide
3968 * Use this flag to lock audio focus so granting is temporarily disabled.
3969 * <br>This flag can only be used by owners of a registered
3970 * {@link android.media.audiopolicy.AudioPolicy} in
3971 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
3972 */
3973 @SystemApi
3974 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07003975
3976 /**
3977 * @hide
3978 * flag set on test API calls,
3979 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
3980 * note that it isn't used in conjunction with other flags, it is passed as the single
3981 * value for flags */
3982 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003983 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003984 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
3985 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003986 /** @hide */
3987 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003988 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003989
3990 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003991 * Request audio focus.
3992 * See the {@link AudioFocusRequest} for information about the options available to configure
3993 * your request, and notification of focus gain and loss.
3994 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
3995 * requested.
3996 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
3997 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
3998 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
3999 * is requested without building the {@link AudioFocusRequest} with
4000 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4001 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004002 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004003 */
4004 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004005 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004006 }
4007
4008 /**
4009 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4010 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4011 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4012 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4013 * @throws IllegalArgumentException if passed a null argument
4014 */
4015 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4016 if (focusRequest == null) {
4017 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4018 }
4019 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4020 focusRequest.getAudioAttributes());
4021 }
4022
4023 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004024 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004025 * Request audio focus.
4026 * Send a request to obtain the audio focus. This method differs from
4027 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4028 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004029 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4030 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4031 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4032 * requesting audio focus.
4033 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4034 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4035 * for the playback of driving directions, or notifications sounds.
4036 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4037 * the previous focus owner to keep playing if it ducks its audio output.
4038 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4039 * that benefits from the system not playing disruptive sounds like notifications, for
4040 * usecases such as voice memo recording, or speech recognition.
4041 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4042 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004043 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4044 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004045 * <br>Use 0 when not using any flags for the request, which behaves like
4046 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4047 * focus is granted immediately, or the grant request fails because the system is in a
4048 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004049 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4050 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4051 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4052 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4053 * @throws IllegalArgumentException
4054 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004055 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004056 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004057 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004058 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004059 int durationHint,
4060 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004061 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4062 throw new IllegalArgumentException("Invalid flags 0x"
4063 + Integer.toHexString(flags).toUpperCase());
4064 }
4065 return requestAudioFocus(l, requestAttributes, durationHint,
4066 flags & AUDIOFOCUS_FLAGS_APPS,
4067 null /* no AudioPolicy*/);
4068 }
4069
4070 /**
4071 * @hide
4072 * Request or lock audio focus.
4073 * This method is to be used by system components that have registered an
4074 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4075 * so focus granting is temporarily disabled.
4076 * @param l see the description of the same parameter in
4077 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4078 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4079 * requesting audio focus.
4080 * @param durationHint see the description of the same parameter in
4081 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4082 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004083 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004084 * <br>Use 0 when not using any flags for the request, which behaves like
4085 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4086 * focus is granted immediately, or the grant request fails because the system is in a
4087 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004088 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4089 * focus, or null.
4090 * @return see the description of the same return value in
4091 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4092 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004093 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004094 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004095 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004096 @RequiresPermission(anyOf= {
4097 android.Manifest.permission.MODIFY_PHONE_STATE,
4098 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4099 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004100 public int requestAudioFocus(OnAudioFocusChangeListener l,
4101 @NonNull AudioAttributes requestAttributes,
4102 int durationHint,
4103 int flags,
4104 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004105 // parameter checking
4106 if (requestAttributes == null) {
4107 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4108 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004109 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004110 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004111 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004112 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004113 throw new IllegalArgumentException("Illegal flags 0x"
4114 + Integer.toHexString(flags).toUpperCase());
4115 }
4116 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4117 throw new IllegalArgumentException(
4118 "Illegal null focus listener when flagged as accepting delayed focus grant");
4119 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004120 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4121 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4122 throw new IllegalArgumentException(
4123 "Illegal null focus listener when flagged as pausing instead of ducking");
4124 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004125 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4126 throw new IllegalArgumentException(
4127 "Illegal null audio policy when locking audio focus");
4128 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004129
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004130 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004131 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004132 .setAudioAttributes(requestAttributes)
4133 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4134 == AUDIOFOCUS_FLAG_DELAY_OK)
4135 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4136 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4137 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4138 .build();
4139 return requestAudioFocus(afr, ap);
4140 }
4141
4142 /**
4143 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004144 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4145 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4146 * @param afr the parameters of the request
4147 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4148 * @param clientFakeUid the UID of the client, here an arbitrary int,
4149 * doesn't have to be a real UID
4150 * @param clientTargetSdk the target SDK used by the client
4151 * @return return code indicating status of the request
4152 */
4153 @TestApi
4154 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4155 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4156 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4157 Objects.requireNonNull(afr);
4158 Objects.requireNonNull(clientFakeId);
4159 try {
4160 return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4161 afr.getFocusGain(),
4162 mICallBack,
4163 mAudioFocusDispatcher,
4164 clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
4165 } catch (RemoteException e) {
4166 throw e.rethrowFromSystemServer();
4167 }
4168 }
4169
4170 /**
4171 * @hide
4172 * Test API to abandon audio focus for an arbitrary client.
4173 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4174 * @param afr the parameters used for the request
4175 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4176 * would be requesting
4177 * @return return code indicating status of the request
4178 */
4179 @TestApi
4180 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4181 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4182 @NonNull String clientFakeId) {
4183 Objects.requireNonNull(afr);
4184 Objects.requireNonNull(clientFakeId);
4185 try {
4186 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4187 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4188 } catch (RemoteException e) {
4189 throw e.rethrowFromSystemServer();
4190 }
4191 }
4192
4193 /**
4194 * @hide
4195 * Return the duration of the fade out applied when a player of the given AudioAttributes
4196 * is losing audio focus
4197 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4198 * @return a duration in ms, 0 indicates no fade out is applied
4199 */
4200 @TestApi
4201 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4202 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4203 {
4204 Objects.requireNonNull(aa);
4205 try {
4206 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4207 } catch (RemoteException e) {
4208 throw e.rethrowFromSystemServer();
4209 }
4210 }
4211
4212 /**
4213 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004214 * Request or lock audio focus.
4215 * This method is to be used by system components that have registered an
4216 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4217 * so focus granting is temporarily disabled.
4218 * @param afr see the description of the same parameter in
4219 * {@link #requestAudioFocus(AudioFocusRequest)}
4220 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4221 * focus, or null.
4222 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4223 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4224 * @throws NullPointerException if the AudioFocusRequest is null
4225 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4226 */
4227 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004228 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004229 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4230 if (afr == null) {
4231 throw new NullPointerException("Illegal null AudioFocusRequest");
4232 }
4233 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4234 if (afr.locksFocus() && ap == null) {
4235 throw new IllegalArgumentException(
4236 "Illegal null audio policy when locking audio focus");
4237 }
4238 registerAudioFocusRequest(afr);
4239 final IAudioService service = getService();
4240 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004241 int sdk;
4242 try {
4243 sdk = getContext().getApplicationInfo().targetSdkVersion;
4244 } catch (NullPointerException e) {
4245 // some tests don't have a Context
4246 sdk = Build.VERSION.SDK_INT;
4247 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004248
4249 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4250 final BlockingFocusResultReceiver focusReceiver;
4251 synchronized (mFocusRequestsLock) {
4252 try {
4253 // TODO status contains result and generation counter for ext policy
4254 status = service.requestAudioFocus(afr.getAudioAttributes(),
4255 afr.getFocusGain(), mICallBack,
4256 mAudioFocusDispatcher,
4257 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004258 getContext().getOpPackageName() /* package name */,
4259 getContext().getAttributionTag(),
4260 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004261 ap != null ? ap.cb() : null,
4262 sdk);
4263 } catch (RemoteException e) {
4264 throw e.rethrowFromSystemServer();
4265 }
4266 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4267 // default path with no external focus policy
4268 return status;
4269 }
4270 if (mFocusRequestsAwaitingResult == null) {
4271 mFocusRequestsAwaitingResult =
4272 new HashMap<String, BlockingFocusResultReceiver>(1);
4273 }
4274 focusReceiver = new BlockingFocusResultReceiver(clientId);
4275 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004276 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004277 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4278 if (DEBUG && !focusReceiver.receivedResult()) {
4279 Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4280 }
4281 synchronized (mFocusRequestsLock) {
4282 mFocusRequestsAwaitingResult.remove(clientId);
4283 }
4284 return focusReceiver.requestResult();
4285 }
4286
4287 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4288 private static final class SafeWaitObject {
4289 private boolean mQuit = false;
4290
4291 public void safeNotify() {
4292 synchronized (this) {
4293 mQuit = true;
4294 this.notify();
4295 }
4296 }
4297
4298 public void safeWait(long millis) throws InterruptedException {
4299 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4300 synchronized (this) {
4301 while (!mQuit) {
4302 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4303 if (timeToWait < 0) { break; }
4304 this.wait(timeToWait);
4305 }
4306 }
4307 }
4308 }
4309
4310 private static final class BlockingFocusResultReceiver {
4311 private final SafeWaitObject mLock = new SafeWaitObject();
4312 @GuardedBy("mLock")
4313 private boolean mResultReceived = false;
4314 // request denied by default (e.g. timeout)
4315 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4316 private final String mFocusClientId;
4317
4318 BlockingFocusResultReceiver(String clientId) {
4319 mFocusClientId = clientId;
4320 }
4321
4322 boolean receivedResult() { return mResultReceived; }
4323 int requestResult() { return mFocusRequestResult; }
4324
4325 void notifyResult(int requestResult) {
4326 synchronized (mLock) {
4327 mResultReceived = true;
4328 mFocusRequestResult = requestResult;
4329 mLock.safeNotify();
4330 }
4331 }
4332
4333 public void waitForResult(long timeOutMs) {
4334 synchronized (mLock) {
4335 if (mResultReceived) {
4336 // the result was received before waiting
4337 return;
4338 }
4339 try {
4340 mLock.safeWait(timeOutMs);
4341 } catch (InterruptedException e) { }
4342 }
4343 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004344 }
4345
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004346 /**
4347 * @hide
4348 * Used internally by telephony package to request audio focus. Will cause the focus request
4349 * to be associated with the "voice communication" identifier only used in AudioService
4350 * to identify this use case.
4351 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4352 * the establishment of the call
4353 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4354 * media applications resume after a call
4355 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004356 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004357 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004358 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004359 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004360 service.requestAudioFocus(new AudioAttributes.Builder()
4361 .setInternalLegacyStreamType(streamType).build(),
4362 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004363 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004364 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004365 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004366 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004367 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004368 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004369 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004370 }
4371 }
4372
4373 /**
4374 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004375 * Return the volume ramping time for a sound to be played after the given focus request,
4376 * and to play a sound of the given attributes
4377 * @param focusGain
4378 * @param attr
4379 * @return
4380 */
4381 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004382 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004383 try {
4384 return service.getFocusRampTimeMs(focusGain, attr);
4385 } catch (RemoteException e) {
4386 throw e.rethrowFromSystemServer();
4387 }
4388 }
4389
4390 /**
4391 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004392 * Set the result to the audio focus request received through
4393 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4394 * @param afi the information about the focus requester
4395 * @param requestResult the result to the focus request to be passed to the requester
4396 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4397 */
4398 @SystemApi
4399 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4400 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4401 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4402 if (afi == null) {
4403 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4404 }
4405 if (ap == null) {
4406 throw new IllegalArgumentException("Illegal null AudioPolicy");
4407 }
4408 final IAudioService service = getService();
4409 try {
4410 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4411 } catch (RemoteException e) {
4412 throw e.rethrowFromSystemServer();
4413 }
4414 }
4415
4416 /**
4417 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004418 * Notifies an application with a focus listener of gain or loss of audio focus.
4419 * This method can only be used by owners of an {@link AudioPolicy} configured with
4420 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4421 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4422 * that was received by the {@code AudioPolicy} through
4423 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4424 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4425 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4426 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4427 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4428 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4429 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4430 * <br>For the focus gain, the change type should be the same as the app requested.
4431 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4432 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4433 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4434 * if there was an error sending the request.
4435 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4436 */
4437 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004438 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004439 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4440 @NonNull AudioPolicy ap) {
4441 if (afi == null) {
4442 throw new NullPointerException("Illegal null AudioFocusInfo");
4443 }
4444 if (ap == null) {
4445 throw new NullPointerException("Illegal null AudioPolicy");
4446 }
4447 final IAudioService service = getService();
4448 try {
4449 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4450 } catch (RemoteException e) {
4451 throw e.rethrowFromSystemServer();
4452 }
4453 }
4454
4455 /**
4456 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004457 * Used internally by telephony package to abandon audio focus, typically after a call or
4458 * when ringing ends and the call is rejected or not answered.
4459 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4460 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004461 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004462 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004463 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004464 try {
John Spurlock61560172015-02-06 19:46:04 -05004465 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004466 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004467 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004468 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004469 }
4470 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004471
4472 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004473 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4474 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004475 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004476 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004477 */
4478 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004479 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4480 }
4481
4482 /**
4483 * @hide
4484 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4485 * @param l the listener with which focus was requested.
4486 * @param aa the {@link AudioAttributes} with which audio focus was requested
4487 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004488 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004489 */
4490 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004491 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4492 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004493 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004494 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004495 unregisterAudioFocusRequest(l);
4496 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004497 try {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004498 status = service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004499 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004500 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004501 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004502 }
4503 return status;
4504 }
4505
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004506 //====================================================================
4507 // Remote Control
4508 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004509 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004510 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4511 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004512 * in the application manifest. The package of the component must match that of
4513 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004514 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004515 */
RoboErikb214efb2014-07-24 13:20:30 -07004516 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004517 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004518 if (eventReceiver == null) {
4519 return;
4520 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004521 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004522 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4523 "receiver and context package names don't match");
4524 return;
4525 }
4526 // construct a PendingIntent for the media button and register it
4527 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4528 // the associated intent will be handled by the component being registered
4529 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004530 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004531 0/*requestCode, ignored*/, mediaButtonIntent,
4532 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004533 registerMediaButtonIntent(pi, eventReceiver);
4534 }
4535
4536 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004537 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4538 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4539 * the buttons to go to any PendingIntent. Note that you should only use this form if
4540 * you know you will continue running for the full time until unregistering the
4541 * PendingIntent.
4542 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004543 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4544 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4545 * media button that was pressed.
4546 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004547 */
RoboErikb214efb2014-07-24 13:20:30 -07004548 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004549 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4550 if (eventReceiver == null) {
4551 return;
4552 }
4553 registerMediaButtonIntent(eventReceiver, null);
4554 }
4555
4556 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004557 * @hide
4558 * no-op if (pi == null) or (eventReceiver == null)
4559 */
4560 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004561 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004562 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4563 return;
4564 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004565 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4566 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004567 }
4568
4569 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004570 * Unregister the receiver of MEDIA_BUTTON intents.
4571 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4572 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004573 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004574 */
RoboErikb214efb2014-07-24 13:20:30 -07004575 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004576 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004577 if (eventReceiver == null) {
4578 return;
4579 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004580 // construct a PendingIntent for the media button and unregister it
4581 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4582 // the associated intent will be handled by the component being registered
4583 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004584 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004585 0/*requestCode, ignored*/, mediaButtonIntent,
4586 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004587 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004588 }
4589
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004590 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004591 * Unregister the receiver of MEDIA_BUTTON intents.
4592 * @param eventReceiver same PendingIntent that was registed with
4593 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004594 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004595 */
RoboErikb214efb2014-07-24 13:20:30 -07004596 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004597 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4598 if (eventReceiver == null) {
4599 return;
4600 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004601 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004602 }
4603
4604 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004605 * @hide
4606 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004607 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004608 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004609 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004610 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004611
4612 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004613 * Registers the remote control client for providing information to display on the remote
4614 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004615 * @param rcClient The remote control client from which remote controls will receive
4616 * information to display.
4617 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004618 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004619 */
RoboErikb214efb2014-07-24 13:20:30 -07004620 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004621 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004622 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004623 return;
4624 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004625 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004626 }
4627
4628 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004629 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004630 * remote controls.
4631 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004632 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004633 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004634 */
RoboErikb214efb2014-07-24 13:20:30 -07004635 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004636 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004637 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004638 return;
4639 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004640 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004641 }
4642
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004643 /**
RoboErika66c40b2014-08-15 15:21:41 -07004644 * Registers a {@link RemoteController} instance for it to receive media
4645 * metadata updates and playback state information from applications using
4646 * {@link RemoteControlClient}, and control their playback.
4647 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004648 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004649 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004650 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004651 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004652 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004653 * @return true if the {@link RemoteController} was successfully registered,
4654 * false if an error occurred, due to an internal system error, or
4655 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004656 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004657 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4658 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004659 */
RoboErikb214efb2014-07-24 13:20:30 -07004660 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004661 public boolean registerRemoteController(RemoteController rctlr) {
4662 if (rctlr == null) {
4663 return false;
4664 }
RoboErik430fc482014-06-12 15:49:20 -07004665 rctlr.startListeningToSessions();
4666 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004667 }
4668
4669 /**
RoboErika66c40b2014-08-15 15:21:41 -07004670 * Unregisters a {@link RemoteController}, causing it to no longer receive
4671 * media metadata and playback state information, and no longer be capable
4672 * of controlling playback.
4673 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004674 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004675 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004676 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4677 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004678 */
RoboErikb214efb2014-07-24 13:20:30 -07004679 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004680 public void unregisterRemoteController(RemoteController rctlr) {
4681 if (rctlr == null) {
4682 return;
4683 }
RoboErik430fc482014-06-12 15:49:20 -07004684 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004685 }
4686
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004687
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004688 //====================================================================
4689 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004690 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004691 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004692 * Register the given {@link AudioPolicy}.
4693 * This call is synchronous and blocks until the registration process successfully completed
4694 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004695 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004696 * @return {@link #ERROR} if there was an error communicating with the registration service
4697 * or if the user doesn't have the required
4698 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4699 * {@link #SUCCESS} otherwise.
4700 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004701 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004702 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004703 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004704 return registerAudioPolicyStatic(policy);
4705 }
4706
4707 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004708 if (policy == null) {
4709 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4710 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004711 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004712 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004713 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004714 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07004715 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4716 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004717 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004718 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004719 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004720 } else {
4721 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004722 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004723 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004724 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004725 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004726 }
4727 return SUCCESS;
4728 }
4729
4730 /**
4731 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004732 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004733 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004734 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004735 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004736 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004737 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004738 unregisterAudioPolicyAsyncStatic(policy);
4739 }
4740
4741 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004742 if (policy == null) {
4743 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4744 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004745 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004746 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004747 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004748 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004749 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004750 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004751 }
4752 }
4753
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004754 /**
4755 * @hide
4756 * Unregisters an {@link AudioPolicy} synchronously.
4757 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4758 * associated with mixes of this policy.
4759 * @param policy the non-null {@link AudioPolicy} to unregister.
4760 */
4761 @SystemApi
4762 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4763 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4764 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4765 final IAudioService service = getService();
4766 try {
4767 policy.invalidateCaptorsAndInjectors();
4768 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004769 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004770 } catch (RemoteException e) {
4771 throw e.rethrowFromSystemServer();
4772 }
4773 }
4774
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07004775 /**
4776 * @hide
4777 * @return true if an AudioPolicy was previously registered
4778 */
4779 @TestApi
4780 public boolean hasRegisteredDynamicPolicy() {
4781 final IAudioService service = getService();
4782 try {
4783 return service.hasRegisteredDynamicPolicy();
4784 } catch (RemoteException e) {
4785 throw e.rethrowFromSystemServer();
4786 }
4787 }
4788
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004789 //====================================================================
4790 // Notification of playback activity & playback configuration
4791 /**
4792 * Interface for receiving update notifications about the playback activity on the system.
4793 * Extend this abstract class and register it with
4794 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4795 * to be notified.
4796 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4797 * configuration.
4798 * @see AudioPlaybackConfiguration
4799 */
4800 public static abstract class AudioPlaybackCallback {
4801 /**
4802 * Called whenever the playback activity and configuration has changed.
4803 * @param configs list containing the results of
4804 * {@link AudioManager#getActivePlaybackConfigurations()}.
4805 */
4806 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4807 }
4808
4809 private static class AudioPlaybackCallbackInfo {
4810 final AudioPlaybackCallback mCb;
4811 final Handler mHandler;
4812 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4813 mCb = cb;
4814 mHandler = handler;
4815 }
4816 }
4817
4818 private final static class PlaybackConfigChangeCallbackData {
4819 final AudioPlaybackCallback mCb;
4820 final List<AudioPlaybackConfiguration> mConfigs;
4821
4822 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4823 List<AudioPlaybackConfiguration> configs) {
4824 mCb = cb;
4825 mConfigs = configs;
4826 }
4827 }
4828
4829 /**
4830 * Register a callback to be notified of audio playback changes through
4831 * {@link AudioPlaybackCallback}
4832 * @param cb non-null callback to register
4833 * @param handler the {@link Handler} object for the thread on which to execute
4834 * the callback. If <code>null</code>, the {@link Handler} associated with the main
4835 * {@link Looper} will be used.
4836 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08004837 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4838 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004839 {
4840 if (cb == null) {
4841 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4842 }
4843
4844 synchronized(mPlaybackCallbackLock) {
4845 // lazy initialization of the list of playback callbacks
4846 if (mPlaybackCallbackList == null) {
4847 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4848 }
4849 final int oldCbCount = mPlaybackCallbackList.size();
4850 if (!hasPlaybackCallback_sync(cb)) {
4851 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4852 new ServiceEventHandlerDelegate(handler).getHandler()));
4853 final int newCbCount = mPlaybackCallbackList.size();
4854 if ((oldCbCount == 0) && (newCbCount > 0)) {
4855 // register binder for callbacks
4856 try {
4857 getService().registerPlaybackCallback(mPlayCb);
4858 } catch (RemoteException e) {
4859 throw e.rethrowFromSystemServer();
4860 }
4861 }
4862 } else {
4863 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4864 + "registered callback");
4865 }
4866 }
4867 }
4868
4869 /**
4870 * Unregister an audio playback callback previously registered with
4871 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4872 * @param cb non-null callback to unregister
4873 */
4874 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4875 if (cb == null) {
4876 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4877 }
4878 synchronized(mPlaybackCallbackLock) {
4879 if (mPlaybackCallbackList == null) {
4880 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4881 + " that was never registered");
4882 return;
4883 }
4884 final int oldCbCount = mPlaybackCallbackList.size();
4885 if (removePlaybackCallback_sync(cb)) {
4886 final int newCbCount = mPlaybackCallbackList.size();
4887 if ((oldCbCount > 0) && (newCbCount == 0)) {
4888 // unregister binder for callbacks
4889 try {
4890 getService().unregisterPlaybackCallback(mPlayCb);
4891 } catch (RemoteException e) {
4892 throw e.rethrowFromSystemServer();
4893 }
4894 }
4895 } else {
4896 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4897 + " already unregistered or never registered");
4898 }
4899 }
4900 }
4901
4902 /**
4903 * Returns the current active audio playback configurations of the device
4904 * @return a non-null list of playback configurations. An empty list indicates there is no
4905 * playback active when queried.
4906 * @see AudioPlaybackConfiguration
4907 */
4908 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
4909 final IAudioService service = getService();
4910 try {
4911 return service.getActivePlaybackConfigurations();
4912 } catch (RemoteException e) {
4913 throw e.rethrowFromSystemServer();
4914 }
4915 }
4916
4917 /**
4918 * All operations on this list are sync'd on mPlaybackCallbackLock.
4919 * List is lazy-initialized in
4920 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4921 * List can be null.
4922 */
4923 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
4924 private final Object mPlaybackCallbackLock = new Object();
4925
4926 /**
4927 * Must be called synchronized on mPlaybackCallbackLock
4928 */
4929 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4930 if (mPlaybackCallbackList != null) {
4931 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4932 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4933 return true;
4934 }
4935 }
4936 }
4937 return false;
4938 }
4939
4940 /**
4941 * Must be called synchronized on mPlaybackCallbackLock
4942 */
4943 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4944 if (mPlaybackCallbackList != null) {
4945 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4946 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4947 mPlaybackCallbackList.remove(i);
4948 return true;
4949 }
4950 }
4951 }
4952 return false;
4953 }
4954
4955 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004956 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07004957 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
4958 boolean flush) {
4959 if (flush) {
4960 Binder.flushPendingCommands();
4961 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004962 synchronized(mPlaybackCallbackLock) {
4963 if (mPlaybackCallbackList != null) {
4964 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4965 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
4966 if (arci.mHandler != null) {
4967 final Message m = arci.mHandler.obtainMessage(
4968 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
4969 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
4970 arci.mHandler.sendMessage(m);
4971 }
4972 }
4973 }
4974 }
4975 }
4976
4977 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004978
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004979 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004980 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004981 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004982 * Interface for receiving update notifications about the recording configuration. Extend
4983 * this abstract class and register it with
4984 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
4985 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08004986 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
4987 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07004988 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004989 */
4990 public static abstract class AudioRecordingCallback {
4991 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004992 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07004993 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08004994 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004995 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07004996 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004997 }
4998
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004999 private static class AudioRecordingCallbackInfo {
5000 final AudioRecordingCallback mCb;
5001 final Handler mHandler;
5002 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5003 mCb = cb;
5004 mHandler = handler;
5005 }
5006 }
5007
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005008 private final static class RecordConfigChangeCallbackData {
5009 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005010 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005011
5012 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005013 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005014 mCb = cb;
5015 mConfigs = configs;
5016 }
5017 }
5018
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005019 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005020 * Register a callback to be notified of audio recording changes through
5021 * {@link AudioRecordingCallback}
5022 * @param cb non-null callback to register
5023 * @param handler the {@link Handler} object for the thread on which to execute
5024 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5025 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005026 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005027 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5028 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005029 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005030 if (cb == null) {
5031 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5032 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005033
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005034 synchronized(mRecordCallbackLock) {
5035 // lazy initialization of the list of recording callbacks
5036 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005037 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005038 }
5039 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005040 if (!hasRecordCallback_sync(cb)) {
5041 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5042 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005043 final int newCbCount = mRecordCallbackList.size();
5044 if ((oldCbCount == 0) && (newCbCount > 0)) {
5045 // register binder for callbacks
5046 final IAudioService service = getService();
5047 try {
5048 service.registerRecordingCallback(mRecCb);
5049 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005050 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005051 }
5052 }
5053 } else {
5054 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5055 + "registered callback");
5056 }
5057 }
5058 }
5059
5060 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005061 * Unregister an audio recording callback previously registered with
5062 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5063 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005064 */
5065 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5066 if (cb == null) {
5067 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5068 }
5069 synchronized(mRecordCallbackLock) {
5070 if (mRecordCallbackList == null) {
5071 return;
5072 }
5073 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005074 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005075 final int newCbCount = mRecordCallbackList.size();
5076 if ((oldCbCount > 0) && (newCbCount == 0)) {
5077 // unregister binder for callbacks
5078 final IAudioService service = getService();
5079 try {
5080 service.unregisterRecordingCallback(mRecCb);
5081 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005082 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005083 }
5084 }
5085 } else {
5086 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5087 + " already unregistered or never registered");
5088 }
5089 }
5090 }
5091
5092 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005093 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005094 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005095 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005096 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005097 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005098 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005099 final IAudioService service = getService();
5100 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005101 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005102 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005103 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005104 }
5105 }
5106
5107 /**
5108 * constants for the recording events, to keep in sync
5109 * with frameworks/av/include/media/AudioPolicy.h
5110 */
5111 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005112 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005113 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005114 public static final int RECORD_CONFIG_EVENT_START = 0;
5115 /** @hide */
5116 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5117 /** @hide */
5118 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5119 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005120 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005121 /**
5122 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5123 */
5124 /** @hide */
5125 public static final int RECORD_RIID_INVALID = -1;
5126 /** @hide */
5127 public static final int RECORDER_STATE_STARTED = 0;
5128 /** @hide */
5129 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005130
5131 /**
5132 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005133 * List is lazy-initialized in
5134 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005135 * List can be null.
5136 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005137 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005138 private final Object mRecordCallbackLock = new Object();
5139
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005140 /**
5141 * Must be called synchronized on mRecordCallbackLock
5142 */
5143 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5144 if (mRecordCallbackList != null) {
5145 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5146 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5147 return true;
5148 }
5149 }
5150 }
5151 return false;
5152 }
5153
5154 /**
5155 * Must be called synchronized on mRecordCallbackLock
5156 */
5157 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5158 if (mRecordCallbackList != null) {
5159 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5160 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5161 mRecordCallbackList.remove(i);
5162 return true;
5163 }
5164 }
5165 }
5166 return false;
5167 }
5168
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005169 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005170 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005171 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005172 synchronized(mRecordCallbackLock) {
5173 if (mRecordCallbackList != null) {
5174 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5175 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5176 if (arci.mHandler != null) {
5177 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005178 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5179 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005180 arci.mHandler.sendMessage(m);
5181 }
5182 }
5183 }
5184 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005185 }
5186
5187 };
5188
5189 //=====================================================================
5190
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005191 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005192 * @hide
5193 * Reload audio settings. This method is called by Settings backup
5194 * agent when audio settings are restored and causes the AudioService
5195 * to read and apply restored settings.
5196 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005197 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005198 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005199 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005200 try {
5201 service.reloadAudioSettings();
5202 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005203 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005204 }
5205 }
5206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005207 /**
5208 * {@hide}
5209 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005210 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005211
5212 /**
5213 * Checks whether the phone is in silent mode, with or without vibrate.
5214 *
5215 * @return true if phone is in silent mode, with or without vibrate.
5216 *
5217 * @see #getRingerMode()
5218 *
5219 * @hide pending API Council approval
5220 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005221 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005222 public boolean isSilentMode() {
5223 int ringerMode = getRingerMode();
5224 boolean silentMode =
5225 (ringerMode == RINGER_MODE_SILENT) ||
5226 (ringerMode == RINGER_MODE_VIBRATE);
5227 return silentMode;
5228 }
5229
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005230 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5231 // class is not used by other parts of the framework, which instead use definitions and methods
5232 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5233
Eric Laurent948d3272014-05-16 15:18:45 -07005234 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005235 * The audio device code for representing "no device." */
5236 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5237 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005238 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005239 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5240 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5241 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5242 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005243 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005244 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005245 /** @hide
5246 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005247 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005248 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005249 /** @hide
5250 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005251 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005252 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005253 /** @hide
5254 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005255 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005256 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005257 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005258 * The audio output device code for a USB headphone with attached microphone */
5259 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5260 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005261 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005262 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005263 /** @hide
5264 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5265 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005266 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005267 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005268 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5269 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005270 /** @hide
5271 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005272 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5273 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005274 /** @hide
5275 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005276 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005277 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005278 /** @hide
5279 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005280 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005281 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5282 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005283 /** @hide
5284 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005285 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005286 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5287 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005288 /** @hide
5289 * The audio output device code for S/PDIF (legacy) or HDMI
5290 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005291 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005292 /** @hide
5293 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005294 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005295 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5296 /** @hide
5297 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005298 * docking station
5299 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005300 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005301 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005302 /** @hide
5303 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005304 * docking station
5305 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005306 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005307 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005308 /** @hide
5309 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005310 * mode and the Android device in USB device mode
5311 */
5312 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005313 /** @hide
5314 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005315 * mode and the Android device in USB host mode
5316 */
5317 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005318 /** @hide
5319 * The audio output device code for projection output.
5320 */
5321 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5322 /** @hide
5323 * The audio output device code the telephony voice TX path.
5324 */
5325 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5326 /** @hide
5327 * The audio output device code for an analog jack with line impedance detected.
5328 */
5329 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5330 /** @hide
5331 * The audio output device code for HDMI Audio Return Channel.
5332 */
5333 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5334 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005335 * The audio output device code for HDMI enhanced Audio Return Channel.
5336 */
5337 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5338 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005339 * The audio output device code for S/PDIF digital connection.
5340 */
5341 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5342 /** @hide
5343 * The audio output device code for built-in FM transmitter.
5344 */
5345 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5346 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005347 * The audio output device code for echo reference injection point.
5348 */
5349 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5350 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005351 * The audio output device code for a BLE audio headset.
5352 */
5353 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5354 /** @hide
5355 * The audio output device code for a BLE audio speaker.
5356 */
5357 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5358 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005359 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005360 * used in the future in a set method to select whatever default device is chosen by the
5361 * platform-specific implementation.
5362 */
5363 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5364
Eric Laurent948d3272014-05-16 15:18:45 -07005365 /** @hide
5366 * The audio input device code for default built-in microphone
5367 */
5368 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5369 /** @hide
5370 * The audio input device code for a Bluetooth SCO headset
5371 */
5372 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5373 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5374 /** @hide
5375 * The audio input device code for wired headset microphone
5376 */
5377 public static final int DEVICE_IN_WIRED_HEADSET =
5378 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5379 /** @hide
5380 * The audio input device code for HDMI
5381 */
5382 public static final int DEVICE_IN_HDMI =
5383 AudioSystem.DEVICE_IN_HDMI;
5384 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005385 * The audio input device code for HDMI ARC
5386 */
5387 public static final int DEVICE_IN_HDMI_ARC =
5388 AudioSystem.DEVICE_IN_HDMI_ARC;
5389
5390 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005391 * The audio input device code for HDMI EARC
5392 */
5393 public static final int DEVICE_IN_HDMI_EARC =
5394 AudioSystem.DEVICE_IN_HDMI_EARC;
5395
5396 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005397 * The audio input device code for telephony voice RX path
5398 */
5399 public static final int DEVICE_IN_TELEPHONY_RX =
5400 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5401 /** @hide
5402 * The audio input device code for built-in microphone pointing to the back
5403 */
5404 public static final int DEVICE_IN_BACK_MIC =
5405 AudioSystem.DEVICE_IN_BACK_MIC;
5406 /** @hide
5407 * The audio input device code for analog from a docking station
5408 */
5409 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5410 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5411 /** @hide
5412 * The audio input device code for digital from a docking station
5413 */
5414 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5415 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5416 /** @hide
5417 * The audio input device code for a USB audio accessory. The accessory is in USB host
5418 * mode and the Android device in USB device mode
5419 */
5420 public static final int DEVICE_IN_USB_ACCESSORY =
5421 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5422 /** @hide
5423 * The audio input device code for a USB audio device. The device is in USB device
5424 * mode and the Android device in USB host mode
5425 */
5426 public static final int DEVICE_IN_USB_DEVICE =
5427 AudioSystem.DEVICE_IN_USB_DEVICE;
5428 /** @hide
5429 * The audio input device code for a FM radio tuner
5430 */
5431 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5432 /** @hide
5433 * The audio input device code for a TV tuner
5434 */
5435 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5436 /** @hide
5437 * The audio input device code for an analog jack with line impedance detected
5438 */
5439 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5440 /** @hide
5441 * The audio input device code for a S/PDIF digital connection
5442 */
5443 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005444 /** @hide
5445 * The audio input device code for audio loopback
5446 */
5447 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005448 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005449 * The audio input device code for an echo reference capture point.
5450 */
5451 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5452 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005453 * The audio input device code for a BLE audio headset.
5454 */
5455 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005456
5457 /**
5458 * Return true if the device code corresponds to an output device.
5459 * @hide
5460 */
5461 public static boolean isOutputDevice(int device)
5462 {
5463 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5464 }
5465
5466 /**
5467 * Return true if the device code corresponds to an input device.
5468 * @hide
5469 */
5470 public static boolean isInputDevice(int device)
5471 {
5472 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5473 }
5474
5475
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005476 /**
5477 * Return the enabled devices for the specified output stream type.
5478 *
5479 * @param streamType The stream type to query. One of
5480 * {@link #STREAM_VOICE_CALL},
5481 * {@link #STREAM_SYSTEM},
5482 * {@link #STREAM_RING},
5483 * {@link #STREAM_MUSIC},
5484 * {@link #STREAM_ALARM},
5485 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005486 * {@link #STREAM_DTMF},
5487 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005488 *
5489 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5490 * stream. Zero or more of
5491 * {@link #DEVICE_OUT_EARPIECE},
5492 * {@link #DEVICE_OUT_SPEAKER},
5493 * {@link #DEVICE_OUT_WIRED_HEADSET},
5494 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5495 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5496 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5497 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5498 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5499 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5500 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005501 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005502 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5503 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005504 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5505 * {@link #DEVICE_OUT_USB_DEVICE}.
5506 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5507 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5508 * {@link #DEVICE_OUT_LINE}.
5509 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005510 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005511 * {@link #DEVICE_OUT_SPDIF}.
5512 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005513 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5514 *
5515 * The implementation may support additional device codes beyond those listed, so
5516 * the application should ignore any bits which it does not recognize.
5517 * Note that the information may be imprecise when the implementation
5518 * cannot distinguish whether a particular device is enabled.
5519 *
5520 * {@hide}
5521 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005522 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005523 public int getDevicesForStream(int streamType) {
5524 switch (streamType) {
5525 case STREAM_VOICE_CALL:
5526 case STREAM_SYSTEM:
5527 case STREAM_RING:
5528 case STREAM_MUSIC:
5529 case STREAM_ALARM:
5530 case STREAM_NOTIFICATION:
5531 case STREAM_DTMF:
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005532 case STREAM_ACCESSIBILITY:
Eric Laurent89c3a972020-12-16 15:57:56 +01005533 final IAudioService service = getService();
5534 try {
5535 return service.getDevicesForStream(streamType);
5536 } catch (RemoteException e) {
5537 throw e.rethrowFromSystemServer();
5538 }
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005539 default:
5540 return 0;
5541 }
5542 }
5543
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005544 /**
5545 * @hide
5546 * Get the audio devices that would be used for the routing of the given audio attributes.
5547 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5548 * @return an empty list if there was an issue with the request, a list of audio devices
5549 * otherwise (typically one device, except for duplicated paths).
5550 */
5551 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005552 @RequiresPermission(anyOf = {
5553 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5554 android.Manifest.permission.QUERY_AUDIO_STATE
5555 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005556 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005557 @NonNull AudioAttributes attributes) {
5558 Objects.requireNonNull(attributes);
5559 final IAudioService service = getService();
5560 try {
5561 return service.getDevicesForAttributes(attributes);
5562 } catch (RemoteException e) {
5563 throw e.rethrowFromSystemServer();
5564 }
5565 }
5566
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005567 /**
5568 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005569 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02005570 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5571 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005572 */
5573 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5574 /**
5575 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005576 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02005577 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005578 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005579 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005580 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5581 /**
5582 * @hide
5583 * Volume behavior for an audio device where the volume is always set to provide no attenuation
5584 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005585 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005586 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005587 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005588 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5589 /**
5590 * @hide
5591 * Volume behavior for an audio device where the volume is either set to muted, or to provide
5592 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005593 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005594 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005595 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005596 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5597 /**
5598 * @hide
5599 * Volume behavior for an audio device where no software attenuation is applied, and
5600 * the volume is kept synchronized between the host and the device itself through a
5601 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005602 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005603 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005604 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005605 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5606 /**
5607 * @hide
5608 * Volume behavior for an audio device where no software attenuation is applied, and
5609 * the volume is kept synchronized between the host and the device itself through a
5610 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5611 * normal vs in phone call).
5612 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02005613 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005614 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005615 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005616 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5617
5618 /** @hide */
5619 @IntDef({
5620 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5621 DEVICE_VOLUME_BEHAVIOR_FULL,
5622 DEVICE_VOLUME_BEHAVIOR_FIXED,
5623 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5624 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5625 })
5626 @Retention(RetentionPolicy.SOURCE)
5627 public @interface DeviceVolumeBehavior {}
5628
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005629 /** @hide */
5630 @IntDef({
5631 DEVICE_VOLUME_BEHAVIOR_UNSET,
5632 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5633 DEVICE_VOLUME_BEHAVIOR_FULL,
5634 DEVICE_VOLUME_BEHAVIOR_FIXED,
5635 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5636 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5637 })
5638 @Retention(RetentionPolicy.SOURCE)
5639 public @interface DeviceVolumeBehaviorState {}
5640
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005641 /**
5642 * @hide
5643 * Throws IAE on an invalid volume behavior value
5644 * @param volumeBehavior behavior value to check
5645 */
5646 public static void enforceValidVolumeBehavior(int volumeBehavior) {
5647 switch (volumeBehavior) {
5648 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5649 case DEVICE_VOLUME_BEHAVIOR_FULL:
5650 case DEVICE_VOLUME_BEHAVIOR_FIXED:
5651 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5652 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5653 return;
5654 default:
5655 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5656 }
5657 }
5658
5659 /**
5660 * @hide
5661 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005662 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5663 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5664 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5665 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5666 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5667 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005668 * @param deviceVolumeBehavior one of the device behaviors
5669 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005670 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005671 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5672 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5673 @DeviceVolumeBehavior int deviceVolumeBehavior) {
5674 // verify arguments (validity of device type is enforced in server)
5675 Objects.requireNonNull(device);
5676 enforceValidVolumeBehavior(deviceVolumeBehavior);
5677 // communicate with service
5678 final IAudioService service = getService();
5679 try {
5680 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5681 mApplicationContext.getOpPackageName());
5682 } catch (RemoteException e) {
5683 throw e.rethrowFromSystemServer();
5684 }
5685 }
5686
5687 /**
5688 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005689 * Returns the volume device behavior for the given audio device
5690 * @param device the audio device
5691 * @return the volume behavior for the device
5692 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005693 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005694 @RequiresPermission(anyOf = {
5695 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5696 android.Manifest.permission.QUERY_AUDIO_STATE
5697 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02005698 public @DeviceVolumeBehavior
5699 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005700 // verify arguments (validity of device type is enforced in server)
5701 Objects.requireNonNull(device);
5702 // communicate with service
5703 final IAudioService service = getService();
5704 try {
5705 return service.getDeviceVolumeBehavior(device);
5706 } catch (RemoteException e) {
5707 throw e.rethrowFromSystemServer();
5708 }
5709 }
5710
kholoud mohamed37839212021-03-15 16:49:06 +00005711 /**
5712 * @hide
5713 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5714 */
5715 @TestApi
5716 @RequiresPermission(anyOf = {
5717 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5718 android.Manifest.permission.QUERY_AUDIO_STATE
5719 })
5720 public boolean isFullVolumeDevice() {
5721 final AudioAttributes attributes = new AudioAttributes.Builder()
5722 .setUsage(AudioAttributes.USAGE_MEDIA)
5723 .build();
5724 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5725 for (AudioDeviceAttributes device : devices) {
5726 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5727 return true;
5728 }
5729 }
5730 return false;
5731 }
5732
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005733 /**
5734 * Indicate wired accessory connection state change.
5735 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5736 * @param state new connection state: 1 connected, 0 disconnected
5737 * @param name device name
5738 * {@hide}
5739 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005740 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07005741 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul McLean10804eb2015-01-28 11:16:35 -08005742 public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005743 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005744 try {
John Spurlock90874332015-03-10 16:00:54 -04005745 service.setWiredDeviceConnectionState(type, state, address, name,
Marco Nelissena80ac052015-03-12 16:17:45 -07005746 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005747 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005748 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005749 }
5750 }
5751
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00005752 /**
wescande7c17ba0c2021-07-30 16:46:14 +02005753 * Indicate Bluetooth profile connection state change.
5754 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
5755 * <code>previousDevice</code>
5756 * This operation is asynchronous.
5757 *
5758 * @param newDevice Bluetooth device connected or null if there is no new devices
5759 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
5760 * devices
5761 * @param info contain all info related to the device. {@link BtProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005762 * {@hide}
5763 */
wescande7c17ba0c2021-07-30 16:46:14 +02005764 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5765 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
5766 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
5767 @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005768 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005769 try {
wescande7c17ba0c2021-07-30 16:46:14 +02005770 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005771 } catch (RemoteException e) {
5772 throw e.rethrowFromSystemServer();
5773 }
5774 }
5775
Jeff Sharkey098d5802012-04-26 17:30:34 -07005776 /** {@hide} */
5777 public IRingtonePlayer getRingtonePlayer() {
5778 try {
5779 return getService().getRingtonePlayer();
5780 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005781 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005782 }
5783 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005784
5785 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005786 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07005787 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
5788 * should use this value as a default, and offer the user the option to override it.
5789 * The low latency output stream is typically either the device's primary output stream,
5790 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005791 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005792 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005793 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5794 "android.media.property.OUTPUT_SAMPLE_RATE";
5795
5796 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005797 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07005798 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
5799 * should use this value as a minimum, and offer the user the option to override it.
5800 * The low latency output stream is typically either the device's primary output stream,
5801 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005802 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005803 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005804 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
5805 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
5806
5807 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07005808 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
5809 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5810 */
5811 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
5812 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
5813
5814 /**
5815 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
5816 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5817 */
5818 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
5819 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
5820
5821 /**
ragoa7cc59c2015-12-02 11:31:15 -08005822 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
5823 * available and supported with the expected frequency range and level response.
5824 */
5825 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
5826 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
5827 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005828 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07005829 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07005830 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
5831 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08005832 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
5833 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
5834 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07005835 * @return A string representing the associated value for that property key,
5836 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07005837 */
5838 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07005839 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
5840 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
5841 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
5842 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
5843 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
5844 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07005845 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07005846 // Will throw a RuntimeException Resources.NotFoundException if this config value is
5847 // not found.
5848 return String.valueOf(getContext().getResources().getBoolean(
5849 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07005850 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07005851 return String.valueOf(getContext().getResources().getBoolean(
5852 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08005853 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
5854 return String.valueOf(getContext().getResources().getBoolean(
5855 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07005856 } else {
5857 // null or unknown key
5858 return null;
5859 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005860 }
5861
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005862 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08005863 * @hide
5864 * Sets an additional audio output device delay in milliseconds.
5865 *
5866 * The additional output delay is a request to the output device to
5867 * delay audio presentation (generally with respect to video presentation for better
5868 * synchronization).
5869 * It may not be supported by all output devices,
5870 * and typically increases the audio latency by the amount of additional
5871 * audio delay requested.
5872 *
5873 * If additional audio delay is supported by an audio output device,
5874 * it is expected to be supported for all output streams (and configurations)
5875 * opened on that device.
5876 *
5877 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07005878 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08005879 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
5880 * @return true if successful, false if the device does not support output device delay
5881 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
5882 */
5883 @SystemApi
5884 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5885 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07005886 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005887 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005888 try {
5889 return getService().setAdditionalOutputDeviceDelay(
5890 new AudioDeviceAttributes(device), delayMillis);
5891 } catch (RemoteException e) {
5892 throw e.rethrowFromSystemServer();
5893 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005894 }
5895
5896 /**
5897 * @hide
5898 * Returns the current additional audio output device delay in milliseconds.
5899 *
5900 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5901 * @return the additional output device delay. This is a non-negative number.
5902 * {@code 0} is returned if unsupported.
5903 */
5904 @SystemApi
5905 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07005906 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005907 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005908 try {
5909 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
5910 } catch (RemoteException e) {
5911 throw e.rethrowFromSystemServer();
5912 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005913 }
5914
5915 /**
5916 * @hide
5917 * Returns the maximum additional audio output device delay in milliseconds.
5918 *
5919 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5920 * @return the maximum output device delay in milliseconds that can be set.
5921 * This is a non-negative number
5922 * representing the additional audio delay supported for the device.
5923 * {@code 0} is returned if unsupported.
5924 */
5925 @SystemApi
5926 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07005927 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005928 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005929 try {
5930 return getService().getMaxAdditionalOutputDeviceDelay(
5931 new AudioDeviceAttributes(device));
5932 } catch (RemoteException e) {
5933 throw e.rethrowFromSystemServer();
5934 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005935 }
5936
5937 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005938 * Returns the estimated latency for the given stream type in milliseconds.
5939 *
5940 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
5941 * a better solution.
5942 * @hide
5943 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005944 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005945 public int getOutputLatency(int streamType) {
5946 return AudioSystem.getOutputLatency(streamType);
5947 }
5948
John Spurlock3346a802014-05-20 16:25:37 -04005949 /**
5950 * Registers a global volume controller interface. Currently limited to SystemUI.
5951 *
5952 * @hide
5953 */
5954 public void setVolumeController(IVolumeController controller) {
5955 try {
5956 getService().setVolumeController(controller);
5957 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005958 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04005959 }
5960 }
5961
5962 /**
John Spurlock33f4e042014-07-11 13:10:58 -04005963 * Notify audio manager about volume controller visibility changes.
5964 * Currently limited to SystemUI.
5965 *
5966 * @hide
5967 */
5968 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
5969 try {
5970 getService().notifyVolumeControllerVisible(controller, visible);
5971 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005972 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04005973 }
5974 }
5975
5976 /**
John Spurlock3346a802014-05-20 16:25:37 -04005977 * Only useful for volume controllers.
5978 * @hide
5979 */
John Spurlock3346a802014-05-20 16:25:37 -04005980 public boolean isStreamAffectedByRingerMode(int streamType) {
5981 try {
5982 return getService().isStreamAffectedByRingerMode(streamType);
5983 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005984 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04005985 }
5986 }
5987
5988 /**
5989 * Only useful for volume controllers.
5990 * @hide
5991 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05005992 public boolean isStreamAffectedByMute(int streamType) {
5993 try {
5994 return getService().isStreamAffectedByMute(streamType);
5995 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005996 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05005997 }
5998 }
5999
6000 /**
6001 * Only useful for volume controllers.
6002 * @hide
6003 */
John Spurlock3346a802014-05-20 16:25:37 -04006004 public void disableSafeMediaVolume() {
6005 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006006 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006007 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006008 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006009 }
6010 }
Eric Laurenta198a292014-02-18 16:26:17 -08006011
6012 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006013 * Only useful for volume controllers.
6014 * @hide
6015 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006016 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006017 public void setRingerModeInternal(int ringerMode) {
6018 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006019 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006020 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006021 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006022 }
6023 }
6024
6025 /**
6026 * Only useful for volume controllers.
6027 * @hide
6028 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006029 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006030 public int getRingerModeInternal() {
6031 try {
6032 return getService().getRingerModeInternal();
6033 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006034 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006035 }
6036 }
6037
6038 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006039 * Only useful for volume controllers.
6040 * @hide
6041 */
6042 public void setVolumePolicy(VolumePolicy policy) {
6043 try {
6044 getService().setVolumePolicy(policy);
6045 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006046 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006047 }
6048 }
6049
6050 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006051 * Set Hdmi Cec system audio mode.
6052 *
6053 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006054 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006055 * @hide
6056 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006057 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006058 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006059 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006060 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006061 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006062 }
6063 }
6064
6065 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006066 * Returns true if Hdmi Cec system audio mode is supported.
6067 *
6068 * @hide
6069 */
6070 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006071 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006072 public boolean isHdmiSystemAudioSupported() {
6073 try {
6074 return getService().isHdmiSystemAudioSupported();
6075 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006076 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006077 }
6078 }
6079
6080 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006081 * Return codes for listAudioPorts(), createAudioPatch() ...
6082 */
6083
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006084 /** @hide */
6085 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006086 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006087 /**
6088 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006089 */
6090 public static final int ERROR = AudioSystem.ERROR;
6091 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006092 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006093 */
6094 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6095 /** @hide
6096 */
6097 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6098 /** @hide
6099 */
6100 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6101 /** @hide
6102 */
6103 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006104 /**
6105 * An error code indicating that the object reporting it is no longer valid and needs to
6106 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006107 */
6108 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6109
6110 /**
6111 * Returns a list of descriptors for all audio ports managed by the audio framework.
6112 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6113 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6114 * See AudioPort for a list of attributes of each audio port.
6115 * @param ports An AudioPort ArrayList where the list will be returned.
6116 * @hide
6117 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006118 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006119 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006120 return updateAudioPortCache(ports, null, null);
6121 }
6122
6123 /**
6124 * Returns a list of descriptors for all audio ports managed by the audio framework as
6125 * it was before the last update calback.
6126 * @param ports An AudioPort ArrayList where the list will be returned.
6127 * @hide
6128 */
6129 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6130 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006131 }
6132
6133 /**
6134 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6135 * @see listAudioPorts(ArrayList<AudioPort>)
6136 * @hide
6137 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006138 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006139 if (devices == null) {
6140 return ERROR_BAD_VALUE;
6141 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006142 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006143 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006144 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006145 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006146 }
6147 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006148 }
6149
6150 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006151 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6152 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6153 * @hide
6154 */
6155 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6156 if (devices == null) {
6157 return ERROR_BAD_VALUE;
6158 }
6159 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6160 int status = updateAudioPortCache(null, null, ports);
6161 if (status == SUCCESS) {
6162 filterDevicePorts(ports, devices);
6163 }
6164 return status;
6165 }
6166
6167 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6168 ArrayList<AudioDevicePort> devices) {
6169 devices.clear();
6170 for (int i = 0; i < ports.size(); i++) {
6171 if (ports.get(i) instanceof AudioDevicePort) {
6172 devices.add((AudioDevicePort)ports.get(i));
6173 }
6174 }
6175 }
6176
6177 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006178 * Create a connection between two or more devices. The framework will reject the request if
6179 * device types are not compatible or the implementation does not support the requested
6180 * configuration.
6181 * NOTE: current implementation is limited to one source and one sink per patch.
6182 * @param patch AudioPatch array where the newly created patch will be returned.
6183 * As input, if patch[0] is not null, the specified patch will be replaced by the
6184 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6185 * patch and allows the implementation to optimize transitions.
6186 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6187 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6188 *
6189 * @return - {@link #SUCCESS} if connection is successful.
6190 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6191 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6192 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6193 * a patch.
6194 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6195 * - {@link #ERROR} if patch cannot be connected for any other reason.
6196 *
6197 * patch[0] contains the newly created patch
6198 * @hide
6199 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006200 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006201 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006202 AudioPortConfig[] sources,
6203 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006204 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006205 }
6206
6207 /**
6208 * Releases an existing audio patch connection.
6209 * @param patch The audio patch to disconnect.
6210 * @return - {@link #SUCCESS} if disconnection is successful.
6211 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6212 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6213 * a patch.
6214 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6215 * - {@link #ERROR} if patch cannot be released for any other reason.
6216 * @hide
6217 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006218 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006219 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006220 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006221 }
6222
6223 /**
6224 * List all existing connections between audio ports.
6225 * @param patches An AudioPatch array where the list will be returned.
6226 * @hide
6227 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006228 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006229 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006230 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006231 }
6232
6233 /**
6234 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6235 * AudioGain.buildConfig()
6236 * @hide
6237 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006238 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006239 if (port == null || gain == null) {
6240 return ERROR_BAD_VALUE;
6241 }
6242 AudioPortConfig activeConfig = port.activeConfig();
6243 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6244 activeConfig.channelMask(), activeConfig.format(), gain);
6245 config.mConfigMask = AudioPortConfig.GAIN;
6246 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006247 }
6248
6249 /**
6250 * Listener registered by client to be notified upon new audio port connections,
6251 * disconnections or attributes update.
6252 * @hide
6253 */
6254 public interface OnAudioPortUpdateListener {
6255 /**
6256 * Callback method called upon audio port list update.
6257 * @param portList the updated list of audio ports
6258 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006259 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006260
6261 /**
6262 * Callback method called upon audio patch list update.
6263 * @param patchList the updated list of audio patches
6264 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006265 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006266
6267 /**
6268 * Callback method called when the mediaserver dies
6269 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006270 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006271 }
6272
6273 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006274 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006275 * @hide
6276 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006277 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006278 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006279 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006280 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006281 }
6282
6283 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006284 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006285 * @hide
6286 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006287 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006288 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006289 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006290 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006291
6292 //
6293 // AudioPort implementation
6294 //
6295
6296 static final int AUDIOPORT_GENERATION_INIT = 0;
Eric Laurentf076db42015-01-14 13:23:27 -08006297 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT);
6298 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006299 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurentf076db42015-01-14 13:23:27 -08006300 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006301
Eric Laurentf076db42015-01-14 13:23:27 -08006302 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006303 int generation;
Eric Laurentf076db42015-01-14 13:23:27 -08006304 synchronized (sAudioPortGeneration) {
6305 generation = sAudioPortGeneration;
6306 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006307 }
6308 return generation;
6309 }
6310
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006311 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6312 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006313 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006314 synchronized (sAudioPortGeneration) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006315
Eric Laurentf076db42015-01-14 13:23:27 -08006316 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006317 int[] patchGeneration = new int[1];
6318 int[] portGeneration = new int[1];
6319 int status;
6320 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6321 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6322
6323 do {
6324 newPorts.clear();
6325 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006326 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006327 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006328 return status;
6329 }
6330 newPatches.clear();
6331 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006332 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006333 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006334 return status;
6335 }
jiabinc4ecaa52017-09-26 14:28:41 -07006336 // Loop until patch generation is the same as port generation unless audio ports
6337 // and audio patches are not null.
6338 } while (patchGeneration[0] != portGeneration[0]
6339 && (ports == null || patches == null));
6340 // If the patch generation doesn't equal port generation, return ERROR here in case
6341 // of mismatch between audio ports and audio patches.
6342 if (patchGeneration[0] != portGeneration[0]) {
6343 return ERROR;
6344 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006345
6346 for (int i = 0; i < newPatches.size(); i++) {
6347 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006348 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6349 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006350 newPatches.get(i).sources()[j] = portCfg;
6351 }
6352 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006353 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6354 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006355 newPatches.get(i).sinks()[j] = portCfg;
6356 }
6357 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006358 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6359 AudioPatch newPatch = i.next();
6360 boolean hasInvalidPort = false;
6361 for (AudioPortConfig portCfg : newPatch.sources()) {
6362 if (portCfg == null) {
6363 hasInvalidPort = true;
6364 break;
6365 }
6366 }
6367 for (AudioPortConfig portCfg : newPatch.sinks()) {
6368 if (portCfg == null) {
6369 hasInvalidPort = true;
6370 break;
6371 }
6372 }
6373 if (hasInvalidPort) {
6374 // Temporarily remove patches with invalid ports. One who created the patch
6375 // is responsible for dealing with the port change.
6376 i.remove();
6377 }
6378 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006379
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006380 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006381 sAudioPortsCached = newPorts;
6382 sAudioPatchesCached = newPatches;
6383 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006384 }
6385 if (ports != null) {
6386 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006387 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006388 }
6389 if (patches != null) {
6390 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006391 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006392 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006393 if (previousPorts != null) {
6394 previousPorts.clear();
6395 previousPorts.addAll(sPreviousAudioPortsCached);
6396 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006397 }
6398 return SUCCESS;
6399 }
6400
Eric Laurentf076db42015-01-14 13:23:27 -08006401 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006402 AudioPort port = portCfg.port();
6403 int k;
6404 for (k = 0; k < ports.size(); k++) {
6405 // compare handles because the port returned by JNI is not of the correct
6406 // subclass
6407 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006408 port = ports.get(k);
6409 break;
6410 }
6411 }
6412 if (k == ports.size()) {
6413 // this hould never happen
6414 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
6415 return null;
6416 }
6417 AudioGainConfig gainCfg = portCfg.gain();
6418 if (gainCfg != null) {
6419 AudioGain gain = port.gain(gainCfg.index());
6420 gainCfg = gain.buildConfig(gainCfg.mode(),
6421 gainCfg.channelMask(),
6422 gainCfg.values(),
6423 gainCfg.rampDurationMs());
6424 }
6425 return port.buildConfig(portCfg.samplingRate(),
6426 portCfg.channelMask(),
6427 portCfg.format(),
6428 gainCfg);
6429 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006430
6431 private OnAmPortUpdateListener mPortListener = null;
6432
6433 /**
6434 * The message sent to apps when the contents of the device list changes if they provide
Andrew Solovay5c05ded2018-10-02 14:14:42 -07006435 * a {@link Handler} object to addOnAudioDeviceConnectionListener().
Paul McLeane3383cc2015-05-08 11:41:20 -07006436 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006437 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6438 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6439 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006440
Paul McLean8e6c9f42015-05-19 11:13:41 -07006441 /**
6442 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6443 */
Jack He89f97982018-05-02 19:10:56 -07006444 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006445 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006446
6447 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006448 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6449 * the results list to only those device types they are interested in.
6450 */
6451 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07006452 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6453 * source (i.e. input) audio devices.
6454 */
6455 public static final int GET_DEVICES_INPUTS = 0x0001;
6456
6457 /**
6458 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6459 * sink (i.e. output) audio devices.
6460 */
6461 public static final int GET_DEVICES_OUTPUTS = 0x0002;
6462
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006463 /** @hide */
6464 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6465 GET_DEVICES_INPUTS,
6466 GET_DEVICES_OUTPUTS }
6467 )
6468 @Retention(RetentionPolicy.SOURCE)
6469 public @interface AudioDeviceRole {}
6470
Paul McLeane3383cc2015-05-08 11:41:20 -07006471 /**
6472 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6473 * source and sink devices.
6474 */
6475 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6476
6477 /**
6478 * Determines if a given AudioDevicePort meets the specified filter criteria.
6479 * @param port The port to test.
6480 * @param flags A set of bitflags specifying the criteria to test.
6481 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6482 **/
6483 private static boolean checkFlags(AudioDevicePort port, int flags) {
6484 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6485 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6486 }
6487
Paul McLean11354572015-08-07 12:50:48 -06006488 private static boolean checkTypes(AudioDevicePort port) {
6489 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07006490 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06006491 }
6492
Paul McLeane3383cc2015-05-08 11:41:20 -07006493 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006494 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6495 * currently connected to the system and meeting the criteria specified in the
6496 * <code>flags</code> parameter.
Paul McLeane3383cc2015-05-08 11:41:20 -07006497 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006498 * @see #GET_DEVICES_OUTPUTS
6499 * @see #GET_DEVICES_INPUTS
6500 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07006501 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6502 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006503 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006504 return getDevicesStatic(flags);
6505 }
6506
Paul McLean8e6c9f42015-05-19 11:13:41 -07006507 /**
6508 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6509 * objects from the current (internal) AudioDevicePort list.
6510 */
Paul McLean03346882015-05-12 15:36:56 -07006511 private static AudioDeviceInfo[]
6512 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006513
Paul McLean8e6c9f42015-05-19 11:13:41 -07006514 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07006515 int numRecs = 0;
6516 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006517 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006518 numRecs++;
6519 }
6520 }
6521
Paul McLean8e6c9f42015-05-19 11:13:41 -07006522 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07006523 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6524 int slot = 0;
6525 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006526 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006527 deviceList[slot++] = new AudioDeviceInfo(port);
6528 }
6529 }
6530
6531 return deviceList;
6532 }
6533
Paul McLean03346882015-05-12 15:36:56 -07006534 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07006535 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6536 * the add/remove callback mechanism to provide a list of the newly added or removed devices
6537 * rather than the whole list and make the app figure it out.
6538 * Note that calling this method with:
6539 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6540 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07006541 */
6542 private static AudioDeviceInfo[] calcListDeltas(
6543 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6544
6545 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6546
6547 AudioDevicePort cur_port = null;
6548 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6549 boolean cur_port_found = false;
6550 cur_port = ports_B.get(cur_index);
6551 for (int prev_index = 0;
6552 prev_index < ports_A.size() && !cur_port_found;
6553 prev_index++) {
6554 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6555 }
6556
6557 if (!cur_port_found) {
6558 delta_ports.add(cur_port);
6559 }
6560 }
6561
6562 return infoListFromPortList(delta_ports, flags);
6563 }
6564
Paul McLeane3383cc2015-05-08 11:41:20 -07006565 /**
Paul McLean03346882015-05-12 15:36:56 -07006566 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6567 * connected to the system and meeting the criteria specified in the <code>flags</code>
6568 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006569 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07006570 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006571 * @see #GET_DEVICES_OUTPUTS
6572 * @see #GET_DEVICES_INPUTS
6573 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07006574 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6575 * @hide
6576 */
6577 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6578 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6579 int status = AudioManager.listAudioDevicePorts(ports);
6580 if (status != AudioManager.SUCCESS) {
6581 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07006582 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07006583 }
6584
6585 return infoListFromPortList(ports, flags);
6586 }
6587
6588 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07006589 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6590 * @param portId The audio port ID to look up for.
6591 * @param flags A set of bitflags specifying the criteria to test.
6592 * @see #GET_DEVICES_OUTPUTS
6593 * @see #GET_DEVICES_INPUTS
6594 * @see #GET_DEVICES_ALL
6595 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6596 * @hide
6597 */
6598 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6599 if (portId == 0) {
6600 return null;
6601 }
6602 AudioDeviceInfo[] devices = getDevicesStatic(flags);
6603 for (AudioDeviceInfo device : devices) {
6604 if (device.getId() == portId) {
6605 return device;
6606 }
6607 }
6608 return null;
6609 }
6610
6611 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006612 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07006613 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006614 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6615 * notifications.
6616 * @param handler Specifies the {@link Handler} object for the thread on which to execute
6617 * the callback. If <code>null</code>, the {@link Handler} associated with the main
6618 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07006619 */
Paul McLean03346882015-05-12 15:36:56 -07006620 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08006621 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07006622 synchronized (mDeviceCallbacks) {
6623 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006624 if (mDeviceCallbacks.size() == 0) {
6625 if (mPortListener == null) {
6626 mPortListener = new OnAmPortUpdateListener();
6627 }
6628 registerAudioPortUpdateListener(mPortListener);
6629 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006630 NativeEventHandlerDelegate delegate =
6631 new NativeEventHandlerDelegate(callback, handler);
6632 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07006633 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07006634 }
6635 }
6636 }
6637
6638 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006639 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07006640 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006641 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08006642 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07006643 */
Paul McLean03346882015-05-12 15:36:56 -07006644 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6645 synchronized (mDeviceCallbacks) {
6646 if (mDeviceCallbacks.containsKey(callback)) {
6647 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07006648 if (mDeviceCallbacks.size() == 0) {
6649 unregisterAudioPortUpdateListener(mPortListener);
6650 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006651 }
6652 }
6653 }
6654
jiabinc0f49442018-01-05 10:23:50 -08006655 /**
6656 * Set port id for microphones by matching device type and address.
6657 * @hide
6658 */
6659 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6660 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6661 for (int i = microphones.size() - 1; i >= 0; i--) {
6662 boolean foundPortId = false;
6663 for (AudioDeviceInfo device : devices) {
6664 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6665 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6666 microphones.get(i).setId(device.getId());
6667 foundPortId = true;
6668 break;
6669 }
6670 }
6671 if (!foundPortId) {
6672 Log.i(TAG, "Failed to find port id for device with type:"
6673 + microphones.get(i).getType() + " address:"
6674 + microphones.get(i).getAddress());
6675 microphones.remove(i);
6676 }
6677 }
6678 }
6679
6680 /**
jiabin589a2362018-02-22 16:21:53 -08006681 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6682 * @hide
6683 */
6684 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6685 int deviceType = deviceInfo.getType();
6686 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6687 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6688 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6689 : MicrophoneInfo.LOCATION_PERIPHERAL;
6690 MicrophoneInfo microphone = new MicrophoneInfo(
6691 deviceInfo.getPort().name() + deviceInfo.getId(),
6692 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6693 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6694 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6695 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6696 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6697 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6698 microphone.setId(deviceInfo.getId());
6699 return microphone;
6700 }
6701
6702 /**
jiabind0be5b22018-04-10 14:10:04 -07006703 * Add {@link MicrophoneInfo} by device information while filtering certain types.
6704 */
6705 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6706 HashSet<Integer> filterTypes) {
6707 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6708 for (AudioDeviceInfo device : devices) {
6709 if (filterTypes.contains(device.getType())) {
6710 continue;
6711 }
6712 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6713 microphones.add(microphone);
6714 }
6715 }
6716
6717 /**
jiabinc0f49442018-01-05 10:23:50 -08006718 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6719 * of all available microphones. The list is empty when no microphones are available
6720 * on the device. An error during the query will result in an IOException being thrown.
6721 *
6722 * @return a list that contains all microphones' characteristics
6723 * @throws IOException if an error occurs.
6724 */
6725 public List<MicrophoneInfo> getMicrophones() throws IOException {
6726 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6727 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006728 HashSet<Integer> filterTypes = new HashSet<>();
6729 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08006730 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07006731 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07006732 if (status != AudioManager.ERROR_INVALID_OPERATION) {
6733 Log.e(TAG, "getMicrophones failed:" + status);
6734 }
6735 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07006736 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6737 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08006738 }
6739 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006740 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6741 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08006742 return microphones;
6743 }
6744
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006745 /**
6746 * Returns a list of audio formats that corresponds to encoding formats
6747 * supported on offload path for A2DP playback.
6748 *
6749 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
6750 * supported for offload A2DP playback
6751 * @hide
6752 */
6753 public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() {
6754 ArrayList<Integer> formatsList = new ArrayList<Integer>();
6755 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>();
6756
6757 int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList);
6758 if (status != AudioManager.SUCCESS) {
6759 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
6760 return codecConfigList;
6761 }
6762
6763 for (Integer format : formatsList) {
6764 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6765 if (btSourceCodec
6766 != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6767 codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
6768 }
6769 }
6770 return codecConfigList;
6771 }
6772
Paul McLeancbeb8a22015-06-10 08:21:27 -07006773 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
6774 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
6775 // of the ports that exist at the time of the last notification.
6776 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
6777
Paul McLeane3383cc2015-05-08 11:41:20 -07006778 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006779 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07006780 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07006781 */
jiabin8c3a7672018-05-22 15:44:21 -07006782 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07006783 int status;
6784
Paul McLeancbeb8a22015-06-10 08:21:27 -07006785 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07006786 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
6787 status = AudioManager.listAudioDevicePorts(current_ports);
6788 if (status != AudioManager.SUCCESS) {
6789 return;
6790 }
6791
Paul McLeancbeb8a22015-06-10 08:21:27 -07006792 if (handler != null) {
6793 // This is the callback for the registration, so send the current list
6794 AudioDeviceInfo[] deviceList =
6795 infoListFromPortList(current_ports, GET_DEVICES_ALL);
6796 handler.sendMessage(
6797 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
6798 } else {
6799 AudioDeviceInfo[] added_devices =
6800 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
6801 AudioDeviceInfo[] removed_devices =
6802 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07006803 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07006804 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
6805 handler = mDeviceCallbacks.valueAt(i).getHandler();
6806 if (handler != null) {
6807 if (removed_devices.length != 0) {
6808 handler.sendMessage(Message.obtain(handler,
6809 MSG_DEVICES_DEVICES_REMOVED,
6810 removed_devices));
6811 }
6812 if (added_devices.length != 0) {
6813 handler.sendMessage(Message.obtain(handler,
6814 MSG_DEVICES_DEVICES_ADDED,
6815 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07006816 }
Paul McLean03346882015-05-12 15:36:56 -07006817 }
6818 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006819 }
6820 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006821
6822 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07006823 }
6824
6825 /**
6826 * Handles Port list update notifications from the AudioManager
6827 */
6828 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
6829 static final String TAG = "OnAmPortUpdateListener";
6830 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07006831 synchronized (mDeviceCallbacks) {
6832 broadcastDeviceListChange_sync(null);
6833 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006834 }
6835
6836 /**
6837 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006838 * Note: We don't do anything with Patches at this time, so ignore this notification.
6839 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07006840 */
6841 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
6842
6843 /**
6844 * Callback method called when the mediaserver dies
6845 */
6846 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07006847 synchronized (mDeviceCallbacks) {
6848 broadcastDeviceListChange_sync(null);
6849 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006850 }
6851 }
6852
Eric Laurent1d3cdce2018-01-20 10:31:21 -08006853
6854 /**
6855 * @hide
6856 * Abstract class to receive event notification about audioserver process state.
6857 */
6858 @SystemApi
6859 public abstract static class AudioServerStateCallback {
6860 public void onAudioServerDown() { }
6861 public void onAudioServerUp() { }
6862 }
6863
6864 private Executor mAudioServerStateExec;
6865 private AudioServerStateCallback mAudioServerStateCb;
6866 private final Object mAudioServerStateCbLock = new Object();
6867
6868 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
6869 new IAudioServerStateDispatcher.Stub() {
6870 @Override
6871 public void dispatchAudioServerStateChange(boolean state) {
6872 Executor exec;
6873 AudioServerStateCallback cb;
6874
6875 synchronized (mAudioServerStateCbLock) {
6876 exec = mAudioServerStateExec;
6877 cb = mAudioServerStateCb;
6878 }
6879
6880 if ((exec == null) || (cb == null)) {
6881 return;
6882 }
6883 if (state) {
6884 exec.execute(() -> cb.onAudioServerUp());
6885 } else {
6886 exec.execute(() -> cb.onAudioServerDown());
6887 }
6888 }
6889 };
6890
6891 /**
6892 * @hide
6893 * Registers a callback for notification of audio server state changes.
6894 * @param executor {@link Executor} to handle the callbacks
6895 * @param stateCallback the callback to receive the audio server state changes
6896 * To remove the callabck, pass a null reference for both executor and stateCallback.
6897 */
6898 @SystemApi
6899 public void setAudioServerStateCallback(@NonNull Executor executor,
6900 @NonNull AudioServerStateCallback stateCallback) {
6901 if (stateCallback == null) {
6902 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
6903 }
6904 if (executor == null) {
6905 throw new IllegalArgumentException(
6906 "Illegal null Executor for the AudioServerStateCallback");
6907 }
6908
6909 synchronized (mAudioServerStateCbLock) {
6910 if (mAudioServerStateCb != null) {
6911 throw new IllegalStateException(
6912 "setAudioServerStateCallback called with already registered callabck");
6913 }
6914 final IAudioService service = getService();
6915 try {
6916 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
6917 } catch (RemoteException e) {
6918 throw e.rethrowFromSystemServer();
6919 }
6920 mAudioServerStateExec = executor;
6921 mAudioServerStateCb = stateCallback;
6922 }
6923 }
6924
6925 /**
6926 * @hide
6927 * Unregisters the callback for notification of audio server state changes.
6928 */
6929 @SystemApi
6930 public void clearAudioServerStateCallback() {
6931 synchronized (mAudioServerStateCbLock) {
6932 if (mAudioServerStateCb != null) {
6933 final IAudioService service = getService();
6934 try {
6935 service.unregisterAudioServerStateDispatcher(
6936 mAudioServerStateDispatcher);
6937 } catch (RemoteException e) {
6938 throw e.rethrowFromSystemServer();
6939 }
6940 }
6941 mAudioServerStateExec = null;
6942 mAudioServerStateCb = null;
6943 }
6944 }
6945
6946 /**
6947 * @hide
6948 * Checks if native audioservice is running or not.
6949 * @return true if native audioservice runs, false otherwise.
6950 */
6951 @SystemApi
6952 public boolean isAudioServerRunning() {
6953 final IAudioService service = getService();
6954 try {
6955 return service.isAudioServerRunning();
6956 } catch (RemoteException e) {
6957 throw e.rethrowFromSystemServer();
6958 }
6959 }
6960
jiabin39940752018-04-02 18:18:45 -07006961 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01006962 * Sets the surround sound mode.
6963 *
6964 * @return true if successful, otherwise false
6965 */
6966 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
6967 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
6968 try {
6969 return getService().setEncodedSurroundMode(mode);
6970 } catch (RemoteException e) {
6971 throw e.rethrowFromSystemServer();
6972 }
6973 }
6974
6975 /**
6976 * Gets the surround sound mode.
6977 *
6978 * @return true if successful, otherwise false
6979 */
Kriti Dang527e66c2021-03-04 10:37:22 +01006980 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
6981 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02006982 return getService().getEncodedSurroundMode(
6983 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01006984 } catch (RemoteException e) {
6985 throw e.rethrowFromSystemServer();
6986 }
6987 }
6988
6989 /**
jiabin39940752018-04-02 18:18:45 -07006990 * @hide
6991 * Returns all surround formats.
6992 * @return a map where the key is a surround format and
6993 * the value indicates the surround format is enabled or not
6994 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02006995 @TestApi
6996 @NonNull
jiabin39940752018-04-02 18:18:45 -07006997 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02006998 try {
6999 return getService().getSurroundFormats();
7000 } catch (RemoteException e) {
7001 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007002 }
jiabin39940752018-04-02 18:18:45 -07007003 }
7004
7005 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007006 * Sets and persists a certain surround format as enabled or not.
7007 * <p>
7008 * This API is called by TvSettings surround sound menu when user enables or disables a
7009 * surround sound format. This setting is persisted as global user setting.
7010 * Applications should revert their changes to surround sound settings unless they intend to
7011 * modify the global user settings across all apps. The framework does not auto-revert an
7012 * application's settings after a lifecycle event. Audio focus is not required to apply these
7013 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007014 *
jiabin39940752018-04-02 18:18:45 -07007015 * @param enabled the required surround format state, true for enabled, false for disabled
7016 * @return true if successful, otherwise false
7017 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007018 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007019 public boolean setSurroundFormatEnabled(
7020 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007021 try {
7022 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7023 } catch (RemoteException e) {
7024 throw e.rethrowFromSystemServer();
7025 }
7026 }
7027
7028 /**
7029 * Gets whether a certain surround format is enabled or not.
7030 * @param audioFormat a surround format
7031 *
7032 * @return whether the required surround format is enabled
7033 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007034 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7035 try {
7036 return getService().isSurroundFormatEnabled(audioFormat);
7037 } catch (RemoteException e) {
7038 throw e.rethrowFromSystemServer();
7039 }
jiabin39940752018-04-02 18:18:45 -07007040 }
7041
7042 /**
7043 * @hide
7044 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007045 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007046 *
Kriti Dang01924232021-03-02 13:51:09 +01007047 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007048 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007049 @TestApi
7050 @NonNull
7051 public List<Integer> getReportedSurroundFormats() {
7052 try {
7053 return getService().getReportedSurroundFormats();
7054 } catch (RemoteException e) {
7055 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007056 }
jiabin39940752018-04-02 18:18:45 -07007057 }
7058
jiabin66f9e722018-11-02 16:20:19 -07007059 /**
7060 * Return if audio haptic coupled playback is supported or not.
7061 *
7062 * @return whether audio haptic playback supported.
7063 */
7064 public static boolean isHapticPlaybackSupported() {
7065 return AudioSystem.isHapticPlaybackSupported();
7066 }
7067
François Gaffie0699fec2018-07-09 14:35:10 +02007068 /**
7069 * @hide
7070 * Introspection API to retrieve audio product strategies.
7071 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7072 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7073 * by OEM without any needs of AOSP patches.
7074 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7075 * strategy refered either by its index or human readable string. It will allow clients
7076 * application to start streaming data using these {@link AudioAttributes} on the selected
7077 * device by Audio Policy Engine.
7078 * @return a (possibly zero-length) array of
7079 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7080 */
7081 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007082 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007083 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007084 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007085 final IAudioService service = getService();
7086 try {
7087 return service.getAudioProductStrategies();
7088 } catch (RemoteException e) {
7089 throw e.rethrowFromSystemServer();
7090 }
7091 }
7092
François Gaffieadcd00a2018-09-18 17:06:26 +02007093 /**
7094 * @hide
7095 * Introspection API to retrieve audio volume groups.
7096 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7097 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007098 * @return a (possibly zero-length) List of
7099 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007100 */
7101 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007102 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007103 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007104 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007105 final IAudioService service = getService();
7106 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007107 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007108 } catch (RemoteException e) {
7109 throw e.rethrowFromSystemServer();
7110 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007111 }
7112
7113 /**
7114 * @hide
7115 * Callback registered by client to be notified upon volume group change.
7116 */
7117 @SystemApi
7118 public abstract static class VolumeGroupCallback {
7119 /**
7120 * Callback method called upon audio volume group change.
7121 * @param group the group for which the volume has changed
7122 */
7123 public void onAudioVolumeGroupChanged(int group, int flags) {}
7124 }
7125
7126 /**
7127 * @hide
7128 * Register an audio volume group change listener.
7129 * @param callback the {@link VolumeGroupCallback} to register
7130 */
7131 @SystemApi
7132 public void registerVolumeGroupCallback(
7133 @NonNull Executor executor,
7134 @NonNull VolumeGroupCallback callback) {
7135 Preconditions.checkNotNull(executor, "executor must not be null");
7136 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7137 sAudioAudioVolumeGroupChangedHandler.init();
7138 // TODO: make use of executor
7139 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7140 }
7141
7142 /**
7143 * @hide
7144 * Unregister an audio volume group change listener.
7145 * @param callback the {@link VolumeGroupCallback} to unregister
7146 */
7147 @SystemApi
7148 public void unregisterVolumeGroupCallback(
7149 @NonNull VolumeGroupCallback callback) {
7150 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7151 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7152 }
jiabin39940752018-04-02 18:18:45 -07007153
jiabinad225202019-03-20 15:22:50 -07007154 /**
7155 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007156 *
7157 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007158 * @param uri the {@link Uri} of the asset.
7159 * @return true if the assert contains haptic channels.
7160 * @hide
7161 */
jiabincfcf1032021-07-01 16:30:50 -07007162 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7163 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007164 try {
jiabincfcf1032021-07-01 16:30:50 -07007165 extractor.setDataSource(context, uri, null);
7166 for (int i = 0; i < extractor.getTrackCount(); i++) {
7167 MediaFormat format = extractor.getTrackFormat(i);
7168 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7169 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7170 return true;
7171 }
7172 }
7173 } catch (IOException e) {
7174 Log.e(TAG, "hasHapticChannels failure:" + e);
7175 }
7176 return false;
7177 }
7178
7179 /**
7180 * Return if an asset contains haptic channels or not.
7181 *
7182 * @param context the {@link Context} to resolve the uri.
7183 * @param uri the {@link Uri} of the asset.
7184 * @return true if the assert contains haptic channels.
7185 * @hide
7186 */
7187 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7188 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07007189
jiabincfcf1032021-07-01 16:30:50 -07007190 if (context != null) {
7191 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07007192 }
7193
7194 Context cachedContext = sContext.get();
7195 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07007196 if (DEBUG) {
7197 Log.d(TAG, "Try to use static context to query if having haptic channels");
7198 }
jiabin0f3339c2021-07-09 11:50:07 -07007199 return hasHapticChannelsImpl(cachedContext, uri);
7200 }
7201
7202 // Try with audio service context, this may fail to get correct result.
7203 if (DEBUG) {
7204 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7205 }
7206 try {
7207 return getService().hasHapticChannels(uri);
7208 } catch (RemoteException e) {
7209 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07007210 }
7211 }
7212
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007213 /**
7214 * Set whether or not there is an active RTT call.
7215 * This method should be called by Telecom service.
7216 * @hide
7217 * TODO: make this a @SystemApi
7218 */
7219 public static void setRttEnabled(boolean rttEnabled) {
7220 try {
7221 getService().setRttEnabled(rttEnabled);
7222 } catch (RemoteException e) {
7223 throw e.rethrowFromSystemServer();
7224 }
7225 }
7226
Jin Seok Park16aeba382020-08-06 12:52:54 +09007227 /**
7228 * Adjusts the volume of the most relevant stream, or the given fallback
7229 * stream.
7230 * <p>
7231 * This method should only be used by applications that replace the
7232 * platform-wide management of audio settings or the main telephony
7233 * application.
7234 * <p>
7235 * This method has no effect if the device implements a fixed volume policy
7236 * as indicated by {@link #isVolumeFixed()}.
7237 * <p>This API checks if the caller has the necessary permissions based on the provided
7238 * component name, uid, and pid values.
7239 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7240 *
7241 * @param suggestedStreamType The stream type that will be used if there
7242 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7243 * valid here.
7244 * @param direction The direction to adjust the volume. One of
7245 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7246 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7247 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7248 * @param flags One or more flags.
7249 * @param packageName the package name of client application
7250 * @param uid the uid of client application
7251 * @param pid the pid of client application
7252 * @param targetSdkVersion the target sdk version of client application
7253 * @see #adjustVolume(int, int)
7254 * @see #adjustStreamVolume(int, int, int)
7255 * @see #setStreamVolume(int, int, int)
7256 * @see #isVolumeFixed()
7257 *
7258 * @hide
7259 */
7260 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7261 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7262 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7263 try {
7264 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7265 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7266 } catch (RemoteException e) {
7267 throw e.rethrowFromSystemServer();
7268 }
7269 }
7270
7271 /**
7272 * Adjusts the volume of a particular stream by one step in a direction.
7273 * <p>
7274 * This method should only be used by applications that replace the platform-wide
7275 * management of audio settings or the main telephony application.
7276 * <p>This method has no effect if the device implements a fixed volume policy
7277 * as indicated by {@link #isVolumeFixed()}.
7278 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7279 * unless the app has been granted Do Not Disturb Access.
7280 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7281 * <p>This API checks if the caller has the necessary permissions based on the provided
7282 * component name, uid, and pid values.
7283 * See {@link #adjustStreamVolume(int, int, int)}.
7284 *
7285 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7286 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7287 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7288 * @param direction The direction to adjust the volume. One of
7289 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7290 * {@link #ADJUST_SAME}.
7291 * @param flags One or more flags.
7292 * @param packageName the package name of client application
7293 * @param uid the uid of client application
7294 * @param pid the pid of client application
7295 * @param targetSdkVersion the target sdk version of client application
7296 * @see #adjustVolume(int, int)
7297 * @see #setStreamVolume(int, int, int)
7298 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7299 * and the caller is not granted notification policy access.
7300 *
7301 * @hide
7302 */
7303 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7304 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7305 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7306 try {
7307 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7308 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7309 } catch (RemoteException e) {
7310 throw e.rethrowFromSystemServer();
7311 }
7312 }
7313
7314 /**
7315 * Sets the volume index for a particular stream.
7316 * <p>This method has no effect if the device implements a fixed volume policy
7317 * as indicated by {@link #isVolumeFixed()}.
7318 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7319 * the app has been granted Do Not Disturb Access.
7320 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7321 * <p>This API checks if the caller has the necessary permissions based on the provided
7322 * component name, uid, and pid values.
7323 * See {@link #setStreamVolume(int, int, int)}.
7324 *
7325 * @param streamType The stream whose volume index should be set.
7326 * @param index The volume index to set. See
7327 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7328 * @param flags One or more flags.
7329 * @param packageName the package name of client application
7330 * @param uid the uid of client application
7331 * @param pid the pid of client application
7332 * @param targetSdkVersion the target sdk version of client application
7333 * @see #getStreamMaxVolume(int)
7334 * @see #getStreamVolume(int)
7335 * @see #isVolumeFixed()
7336 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7337 * and the caller is not granted notification policy access.
7338 *
7339 * @hide
7340 */
7341 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7342 public void setStreamVolumeForUid(int streamType, int index, int flags,
7343 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7344 try {
7345 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7346 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7347 } catch (RemoteException e) {
7348 throw e.rethrowFromSystemServer();
7349 }
7350 }
7351
7352
hjin81.lee4e984e52019-12-05 14:34:52 +09007353 /** @hide
7354 * TODO: make this a @SystemApi */
7355 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7356 public void setMultiAudioFocusEnabled(boolean enabled) {
7357 try {
7358 getService().setMultiAudioFocusEnabled(enabled);
7359 } catch (RemoteException e) {
7360 throw e.rethrowFromSystemServer();
7361 }
7362 }
7363
Eric Laurent43a78de2020-07-24 17:11:15 -07007364
7365 /**
7366 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7367 * For more details on Hardware A/V synchronization please refer to
7368 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7369 * media tunneling documentation</a>.
7370 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7371 * @return the HW A/V sync ID for this audio session (an integer different from 0).
7372 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7373 */
7374 public int getAudioHwSyncForSession(int sessionId) {
7375 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7376 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7377 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7378 }
7379 return hwSyncId;
7380 }
7381
Eric Laurentb36d4a12020-10-09 09:52:49 -07007382 /**
7383 * Selects the audio device that should be used for communication use cases, for instance voice
7384 * or video calls. This method can be used by voice or video chat applications to select a
7385 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01007386 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7387 * {@link #getAvailableCommunicationDevices()}.
7388 * The selection is active as long as the requesting application process lives, until
7389 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007390 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01007391 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007392 * <p>In case of simultaneous requests by multiple applications the priority is given to the
7393 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7394 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7395 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7396 * telephony application with permission
7397 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7398 * <p> If the requested devices is not currently available, the request will be rejected and
7399 * the method will return false.
7400 * <p>This API replaces the following deprecated APIs:
7401 * <ul>
7402 * <li> {@link #startBluetoothSco()}
7403 * <li> {@link #stopBluetoothSco()}
7404 * <li> {@link #setSpeakerphoneOn(boolean)}
7405 * </ul>
7406 * <h4>Example</h4>
7407 * <p>The example below shows how to enable and disable speakerphone mode.
7408 * <pre class="prettyprint">
7409 * // Get an AudioManager instance
7410 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01007411 * AudioDeviceInfo speakerDevice = null;
7412 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7413 * for (AudioDeviceInfo device : devices) {
7414 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7415 * speakerDevice = device;
7416 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007417 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007418 * }
7419 * if (speakerDevice != null) {
7420 * // Turn speakerphone ON.
7421 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
7422 * if (!result) {
7423 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007424 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007425 * // Turn speakerphone OFF.
7426 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007427 * }
7428 * </pre>
7429 * @param device the requested audio device.
7430 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7431 * @throws IllegalArgumentException If an invalid device is specified.
7432 */
Eric Laurent7412f572021-02-11 15:10:31 +01007433 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007434 Objects.requireNonNull(device);
7435 try {
7436 if (device.getId() == 0) {
7437 throw new IllegalArgumentException("In valid device: " + device);
7438 }
Eric Laurent7412f572021-02-11 15:10:31 +01007439 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007440 } catch (RemoteException e) {
7441 throw e.rethrowFromSystemServer();
7442 }
7443 }
7444
7445 /**
7446 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01007447 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007448 */
Eric Laurent7412f572021-02-11 15:10:31 +01007449 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007450 try {
Eric Laurent7412f572021-02-11 15:10:31 +01007451 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007452 } catch (RemoteException e) {
7453 throw e.rethrowFromSystemServer();
7454 }
7455 }
7456
7457 /**
7458 * Returns currently selected audio device for communication.
7459 * <p>This API replaces the following deprecated APIs:
7460 * <ul>
7461 * <li> {@link #isBluetoothScoOn()}
7462 * <li> {@link #isSpeakerphoneOn()}
7463 * </ul>
7464 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01007465 * currently selected for communication use cases. Can be null on platforms
7466 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007467 * is used.
7468 */
7469 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01007470 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007471 try {
7472 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01007473 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7474 } catch (RemoteException e) {
7475 throw e.rethrowFromSystemServer();
7476 }
7477 }
7478
7479 /**
7480 * Returns a list of audio devices that can be selected for communication use cases via
7481 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7482 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7483 */
7484 @NonNull
7485 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7486 try {
7487 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7488 int[] portIds = getService().getAvailableCommunicationDeviceIds();
7489 for (int portId : portIds) {
7490 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7491 if (device == null) {
7492 continue;
7493 }
7494 devices.add(device);
7495 }
7496 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007497 } catch (RemoteException e) {
7498 throw e.rethrowFromSystemServer();
7499 }
7500 }
7501
7502 /**
7503 * @hide
7504 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7505 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7506 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7507 * The method will return null if no device of the provided type is connected.
7508 * If more than one device of the provided type is connected, an object corresponding to the
7509 * first device encountered in the enumeration list will be returned.
7510 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01007511 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007512 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7513 * @throws IllegalArgumentException If an invalid device type is specified.
7514 */
7515 @TestApi
7516 @Nullable
7517 public static AudioDeviceInfo getDeviceInfoFromType(
7518 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01007519 return getDeviceInfoFromTypeAndAddress(deviceType, null);
7520 }
7521
7522 /**
7523 * @hide
7524 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7525 * address provided.
7526 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7527 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7528 * If a null address is provided, the matching will happen on the type only.
7529 * The method will return null if no device of the provided type and address is connected.
7530 * If more than one device of the provided type is connected, an object corresponding to the
7531 * first device encountered in the enumeration list will be returned.
7532 * @param type The device device for which an <code>AudioDeviceInfo</code>
7533 * object is queried.
7534 * @param address The device address for which an <code>AudioDeviceInfo</code>
7535 * object is queried or null if requesting match on type only.
7536 * @return An AudioDeviceInfo object or null if no matching device is connected.
7537 * @throws IllegalArgumentException If an invalid device type is specified.
7538 */
7539 @Nullable
7540 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7541 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007542 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01007543 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007544 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01007545 if (device.getType() == type) {
7546 deviceForType = device;
7547 if (address == null || address.equals(device.getAddress())) {
7548 return device;
7549 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007550 }
7551 }
Eric Laurent7412f572021-02-11 15:10:31 +01007552 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007553 }
7554
7555 /**
7556 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007557 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007558 */
7559 public interface OnCommunicationDeviceChangedListener {
7560 /**
7561 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007562 * @param device the audio device requested for communication use cases.
7563 * Can be null on platforms not supporting
7564 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007565 */
7566 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7567 }
7568
7569 /**
7570 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007571 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007572 * @param executor
7573 * @param listener
7574 */
7575 public void addOnCommunicationDeviceChangedListener(
7576 @NonNull @CallbackExecutor Executor executor,
7577 @NonNull OnCommunicationDeviceChangedListener listener) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007578 synchronized (mCommDevListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007579 final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
7580 CommunicationDeviceDispatcherStub> res =
7581 CallbackUtil.addListener("addOnCommunicationDeviceChangedListener",
7582 executor, listener, mCommDevListeners, mCommDevDispatcherStub,
7583 () -> new CommunicationDeviceDispatcherStub(),
7584 stub -> stub.register(true));
7585 mCommDevListeners = res.first;
7586 mCommDevDispatcherStub = res.second;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007587 }
7588 }
7589
7590 /**
7591 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007592 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007593 * @param listener
7594 */
7595 public void removeOnCommunicationDeviceChangedListener(
7596 @NonNull OnCommunicationDeviceChangedListener listener) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007597 synchronized (mCommDevListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007598 final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
7599 CommunicationDeviceDispatcherStub> res =
7600 CallbackUtil.removeListener("removeOnCommunicationDeviceChangedListener",
7601 listener, mCommDevListeners, mCommDevDispatcherStub,
7602 stub -> stub.register(false));
7603 mCommDevListeners = res.first;
7604 mCommDevDispatcherStub = res.second;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007605 }
7606 }
7607
7608 private final Object mCommDevListenerLock = new Object();
7609 /**
7610 * List of listeners for preferred device for strategy and their associated Executor.
7611 * List is lazy-initialized on first registration
7612 */
7613 @GuardedBy("mCommDevListenerLock")
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007614 private @Nullable
7615 ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>> mCommDevListeners;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007616
7617 @GuardedBy("mCommDevListenerLock")
7618 private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
7619
7620 private final class CommunicationDeviceDispatcherStub
7621 extends ICommunicationDeviceDispatcher.Stub {
7622
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007623 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007624 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007625 if (register) {
7626 getService().registerCommunicationDeviceDispatcher(this);
7627 } else {
7628 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007629 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007630 } catch (RemoteException e) {
7631 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007632 }
7633 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007634
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007635 @Override
7636 @SuppressLint("GuardedBy") // lock applied inside callListeners method
7637 public void dispatchCommunicationDeviceChanged(int portId) {
7638 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7639 CallbackUtil.callListeners(mCommDevListeners, mCommDevListenerLock,
7640 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07007641 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007642 }
7643
Paul McLeane3383cc2015-05-08 11:41:20 -07007644 //---------------------------------------------------------
7645 // Inner classes
7646 //--------------------
7647 /**
7648 * Helper class to handle the forwarding of native events to the appropriate listener
7649 * (potentially) handled in a different thread.
7650 */
7651 private class NativeEventHandlerDelegate {
7652 private final Handler mHandler;
7653
Paul McLean03346882015-05-12 15:36:56 -07007654 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07007655 Handler handler) {
7656 // find the looper for our new event handler
7657 Looper looper;
7658 if (handler != null) {
7659 looper = handler.getLooper();
7660 } else {
7661 // no given handler, use the looper the addListener call was called in
7662 looper = Looper.getMainLooper();
7663 }
7664
7665 // construct the event handler with this looper
7666 if (looper != null) {
7667 // implement the event handler delegate
7668 mHandler = new Handler(looper) {
7669 @Override
7670 public void handleMessage(Message msg) {
7671 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07007672 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07007673 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07007674 if (callback != null) {
7675 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07007676 }
7677 break;
Paul McLean03346882015-05-12 15:36:56 -07007678
7679 case MSG_DEVICES_DEVICES_REMOVED:
7680 if (callback != null) {
7681 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
7682 }
7683 break;
7684
Paul McLeane3383cc2015-05-08 11:41:20 -07007685 default:
7686 Log.e(TAG, "Unknown native event type: " + msg.what);
7687 break;
7688 }
7689 }
7690 };
7691 } else {
7692 mHandler = null;
7693 }
7694 }
7695
7696 Handler getHandler() {
7697 return mHandler;
7698 }
7699 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007700}