blob: d721291ad78f465b2ab450a41ddd48f22a33ecde [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080019import android.annotation.CallbackExecutor;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080020import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070021import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080022import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070023import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.annotation.SdkConstant;
26import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070027import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090028import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060029import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070030import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050031import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070032import android.app.PendingIntent;
Eric Laurent1c3408f2021-11-09 12:09:54 +010033import android.app.compat.CompatChanges;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080034import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070035import android.bluetooth.BluetoothDevice;
Patty46694212021-11-04 21:03:32 +080036import android.bluetooth.BluetoothLeAudioCodecConfig;
Eric Laurent1c3408f2021-11-09 12:09:54 +010037import android.compat.annotation.ChangeId;
38import android.compat.annotation.EnabledSince;
Artur Satayev53fe9662019-12-10 17:47:55 +000039import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070040import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070042import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080043import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -080044import android.media.CallbackUtil.ListenerInfo;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070045import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080046import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070047import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070048import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020049import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080050import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070051import android.media.session.MediaController;
52import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070053import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070054import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070055import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070057import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Handler;
59import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080060import android.os.Looper;
61import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.os.RemoteException;
63import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050064import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010065import android.os.UserHandle;
Lais Andrade724d0cd2021-11-03 19:46:21 +000066import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080067import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070068import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080070import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070071import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080073import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020074import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080075
jiabinc0f49442018-01-05 10:23:50 -080076import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080077import java.lang.annotation.Retention;
78import java.lang.annotation.RetentionPolicy;
jiabin0f3339c2021-07-09 11:50:07 -070079import java.lang.ref.WeakReference;
Eric Laurenta198a292014-02-18 16:26:17 -080080import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070081import java.util.Arrays;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080082import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070083import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090084import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080085import java.util.List;
jiabin39940752018-04-02 18:18:45 -070086import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070087import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090088import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070089import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080090import java.util.concurrent.Executor;
Eric Laurent78eef3a2021-11-09 16:10:42 +010091import java.util.concurrent.Executors;
Jean-Michel Trivi933bf142021-11-19 16:18:52 -080092import java.util.concurrent.TimeUnit;
Eric Laurent700e7342014-05-02 18:33:15 -070093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094/**
95 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060097@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098public class AudioManager {
99
Marco Nelissen29f16932015-04-17 09:50:56 -0700100 private Context mOriginalContext;
101 private Context mApplicationContext;
Joe Onorato86f67862010-11-05 18:57:34 -0700102 private long mVolumeKeyUpTime;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800103 private static final String TAG = "AudioManager";
104 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800105 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200106 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
107 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
jiabin0f3339c2021-07-09 11:50:07 -0700109 private static WeakReference<Context> sContext;
jiabincfcf1032021-07-01 16:30:50 -0700110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 /**
112 * Broadcast intent, a hint for applications that audio is about to become
113 * 'noisy' due to a change in audio outputs. For example, this intent may
114 * be sent when a wired headset is unplugged, or when an A2DP audio
115 * sink is disconnected, and the audio system is about to automatically
116 * switch audio route to the speaker. Applications that are controlling
117 * audio streams may consider pausing, reducing volume or some other action
118 * on receipt of this intent so as not to surprise the user with audio
119 * from the speaker.
120 */
121 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
122 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
123
124 /**
125 * Sticky broadcast intent action indicating that the ringer mode has
126 * changed. Includes the new ringer mode.
127 *
128 * @see #EXTRA_RINGER_MODE
129 */
130 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
131 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
132
133 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500134 * @hide
135 * Sticky broadcast intent action indicating that the internal ringer mode has
136 * changed. Includes the new ringer mode.
137 *
138 * @see #EXTRA_RINGER_MODE
139 */
140 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
141 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
142 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
143
144 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 * The new ringer mode.
146 *
147 * @see #RINGER_MODE_CHANGED_ACTION
148 * @see #RINGER_MODE_NORMAL
149 * @see #RINGER_MODE_SILENT
150 * @see #RINGER_MODE_VIBRATE
151 */
152 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
153
154 /**
155 * Broadcast intent action indicating that the vibrate setting has
156 * changed. Includes the vibrate type and its new setting.
157 *
158 * @see #EXTRA_VIBRATE_TYPE
159 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700160 * @deprecated Applications should maintain their own vibrate policy based on
161 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 */
163 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500164 public static final String VIBRATE_SETTING_CHANGED_ACTION =
165 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
167 /**
168 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700169 * Includes the stream, the new volume and previous volumes.
170 * Notes:
171 * - for internal platform use only, do not make public,
172 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 *
174 * @see #EXTRA_VOLUME_STREAM_TYPE
175 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800176 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 */
178 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100179 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
181
182 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400183 * @hide Broadcast intent when the devices for a particular stream type changes.
184 * Includes the stream, the new devices and previous devices.
185 * Notes:
186 * - for internal platform use only, do not make public,
187 * - never used for "remote" volume changes
188 *
189 * @see #EXTRA_VOLUME_STREAM_TYPE
190 * @see #EXTRA_VOLUME_STREAM_DEVICES
191 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
192 * @see #getDevicesForStream
193 */
194 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
195 public static final String STREAM_DEVICES_CHANGED_ACTION =
196 "android.media.STREAM_DEVICES_CHANGED_ACTION";
197
198 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800199 * @hide Broadcast intent when a stream mute state changes.
200 * Includes the stream that changed and the new mute state
201 *
202 * @see #EXTRA_VOLUME_STREAM_TYPE
203 * @see #EXTRA_STREAM_VOLUME_MUTED
204 */
205 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
206 public static final String STREAM_MUTE_CHANGED_ACTION =
207 "android.media.STREAM_MUTE_CHANGED_ACTION";
208
209 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500210 * @hide Broadcast intent when the master mute state changes.
211 * Includes the the new volume
212 *
213 * @see #EXTRA_MASTER_VOLUME_MUTED
214 */
215 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
216 public static final String MASTER_MUTE_CHANGED_ACTION =
217 "android.media.MASTER_MUTE_CHANGED_ACTION";
218
219 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 * The new vibrate setting for a particular type.
221 *
222 * @see #VIBRATE_SETTING_CHANGED_ACTION
223 * @see #EXTRA_VIBRATE_TYPE
224 * @see #VIBRATE_SETTING_ON
225 * @see #VIBRATE_SETTING_OFF
226 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700227 * @deprecated Applications should maintain their own vibrate policy based on
228 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 */
230 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
231
232 /**
233 * The vibrate type whose setting has changed.
234 *
235 * @see #VIBRATE_SETTING_CHANGED_ACTION
236 * @see #VIBRATE_TYPE_NOTIFICATION
237 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700238 * @deprecated Applications should maintain their own vibrate policy based on
239 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 */
241 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
242
243 /**
244 * @hide The stream type for the volume changed intent.
245 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100246 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
248
249 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700250 * @hide
251 * The stream type alias for the volume changed intent.
252 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
253 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
254 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
255 * {@link #STREAM_MUSIC} on others (e.g. a television).
256 */
257 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
258 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
259
260 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 * @hide The volume associated with the stream for the volume changed intent.
262 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100263 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 public static final String EXTRA_VOLUME_STREAM_VALUE =
265 "android.media.EXTRA_VOLUME_STREAM_VALUE";
266
Eric Laurent9ce379a2010-02-16 06:00:26 -0800267 /**
268 * @hide The previous volume associated with the stream for the volume changed intent.
269 */
270 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
271 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
272
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500273 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400274 * @hide The devices associated with the stream for the stream devices changed intent.
275 */
276 public static final String EXTRA_VOLUME_STREAM_DEVICES =
277 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
278
279 /**
280 * @hide The previous devices associated with the stream for the stream devices changed intent.
281 */
282 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
283 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
284
285 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500286 * @hide The new master volume mute state for the master mute changed intent.
287 * Value is boolean
288 */
289 public static final String EXTRA_MASTER_VOLUME_MUTED =
290 "android.media.EXTRA_MASTER_VOLUME_MUTED";
291
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700292 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800293 * @hide The new stream volume mute state for the stream mute changed intent.
294 * Value is boolean
295 */
296 public static final String EXTRA_STREAM_VOLUME_MUTED =
297 "android.media.EXTRA_STREAM_VOLUME_MUTED";
298
299 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700300 * Broadcast Action: Wired Headset plugged in or unplugged.
301 *
302 * You <em>cannot</em> receive this through components declared
303 * in manifests, only by explicitly registering for it with
304 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
305 * Context.registerReceiver()}.
306 *
307 * <p>The intent will have the following extra values:
308 * <ul>
309 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
310 * <li><em>name</em> - Headset type, human readable string </li>
311 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
312 * </ul>
313 * </ul>
314 */
315 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
316 public static final String ACTION_HEADSET_PLUG =
317 "android.intent.action.HEADSET_PLUG";
318
319 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200320 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700321 *
322 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
323 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
324 * <p>It can only be received by explicitly registering for it with
325 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
326 */
327 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
328 public static final String ACTION_HDMI_AUDIO_PLUG =
329 "android.media.action.HDMI_AUDIO_PLUG";
330
331 /**
332 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
333 * or unplugged.
334 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
335 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700336 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700337
338 /**
339 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
340 * supported by the HDMI device.
341 * The corresponding integer value is only available when the device is plugged in (as expressed
342 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
343 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700344 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700345
346 /**
347 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
348 * the connected HDMI device.
349 * The corresponding array of encoding values is only available when the device is plugged in
350 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
351 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
352 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
353 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700354 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700355
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700356 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700358 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700360 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700362 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700364 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700366 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700368 /** @hide Used to identify the volume of audio streams for phone calls when connected
369 * to bluetooth */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100370 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700372 /** @hide Used to identify the volume of audio streams for enforced system sounds
373 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100374 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700375 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700376 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700377 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700378 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
379 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100380 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700381 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800382 /** Used to identify the volume of audio streams for accessibility prompts */
383 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000384 /** @hide Used to identify the volume of audio streams for virtual assistant */
385 @SystemApi
386 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
387 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 /** Number of audio streams */
390 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700391 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 */
Eric Laurenta553c252009-07-17 12:17:14 -0700393 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394
Paul McLeand6f87c82021-03-31 13:02:41 -0600395 /** @hide */
396 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
397 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
398 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
399 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
400
401 /** @hide */
402 @TestApi
403 public static final int[] getPublicStreamTypes() {
404 return PUBLIC_STREAM_TYPES;
405 }
406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 /**
408 * Increase the ringer volume.
409 *
410 * @see #adjustVolume(int, int)
411 * @see #adjustStreamVolume(int, int, int)
412 */
413 public static final int ADJUST_RAISE = 1;
414
415 /**
416 * Decrease the ringer volume.
417 *
418 * @see #adjustVolume(int, int)
419 * @see #adjustStreamVolume(int, int, int)
420 */
421 public static final int ADJUST_LOWER = -1;
422
423 /**
424 * Maintain the previous ringer volume. This may be useful when needing to
425 * show the volume toast without actually modifying the volume.
426 *
427 * @see #adjustVolume(int, int)
428 * @see #adjustStreamVolume(int, int, int)
429 */
430 public static final int ADJUST_SAME = 0;
431
RoboErik4197cb62015-01-21 15:45:32 -0800432 /**
433 * Mute the volume. Has no effect if the stream is already muted.
434 *
435 * @see #adjustVolume(int, int)
436 * @see #adjustStreamVolume(int, int, int)
437 */
438 public static final int ADJUST_MUTE = -100;
439
440 /**
441 * Unmute the volume. Has no effect if the stream is not muted.
442 *
443 * @see #adjustVolume(int, int)
444 * @see #adjustStreamVolume(int, int, int)
445 */
446 public static final int ADJUST_UNMUTE = 100;
447
448 /**
449 * Toggle the mute state. If muted the stream will be unmuted. If not muted
450 * the stream will be muted.
451 *
452 * @see #adjustVolume(int, int)
453 * @see #adjustStreamVolume(int, int, int)
454 */
455 public static final int ADJUST_TOGGLE_MUTE = 101;
456
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700457 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800458 @IntDef(flag = false, prefix = "ADJUST", value = {
459 ADJUST_RAISE,
460 ADJUST_LOWER,
461 ADJUST_SAME,
462 ADJUST_MUTE,
463 ADJUST_UNMUTE,
464 ADJUST_TOGGLE_MUTE }
465 )
466 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800467 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800468
469 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700470 public static final String adjustToString(int adj) {
471 switch (adj) {
472 case ADJUST_RAISE: return "ADJUST_RAISE";
473 case ADJUST_LOWER: return "ADJUST_LOWER";
474 case ADJUST_SAME: return "ADJUST_SAME";
475 case ADJUST_MUTE: return "ADJUST_MUTE";
476 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
477 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
478 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
479 }
480 }
481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 // Flags should be powers of 2!
483
484 /**
485 * Show a toast containing the current volume.
486 *
487 * @see #adjustStreamVolume(int, int, int)
488 * @see #adjustVolume(int, int)
489 * @see #setStreamVolume(int, int, int)
490 * @see #setRingerMode(int)
491 */
492 public static final int FLAG_SHOW_UI = 1 << 0;
493
494 /**
495 * Whether to include ringer modes as possible options when changing volume.
496 * For example, if true and volume level is 0 and the volume is adjusted
497 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
498 * vibrate mode.
499 * <p>
500 * By default this is on for the ring stream. If this flag is included,
501 * this behavior will be present regardless of the stream type being
502 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700503 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 * @see #adjustVolume(int, int)
505 * @see #adjustStreamVolume(int, int, int)
506 */
507 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
508
509 /**
510 * Whether to play a sound when changing the volume.
511 * <p>
512 * If this is given to {@link #adjustVolume(int, int)} or
513 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
514 * in some cases (for example, the decided stream type is not
515 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
516 * downward).
517 *
518 * @see #adjustStreamVolume(int, int, int)
519 * @see #adjustVolume(int, int)
520 * @see #setStreamVolume(int, int, int)
521 */
522 public static final int FLAG_PLAY_SOUND = 1 << 2;
523
524 /**
525 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
526 * changing volume).
527 */
528 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
529
530 /**
531 * Whether to vibrate if going into the vibrate ringer mode.
532 */
533 public static final int FLAG_VIBRATE = 1 << 4;
534
535 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700536 * Indicates to VolumePanel that the volume slider should be disabled as user
537 * cannot change the stream volume
538 * @hide
539 */
540 public static final int FLAG_FIXED_VOLUME = 1 << 5;
541
542 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700543 * Indicates the volume set/adjust call is for Bluetooth absolute volume
544 * @hide
545 */
546 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
547
548 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400549 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
550 * @hide
551 */
552 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
553
554 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900555 * Indicates the volume call is for Hdmi Cec system audio volume
556 * @hide
557 */
558 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
559
560 /**
RoboErik3c45c292014-07-08 16:47:31 -0700561 * Indicates that this should only be handled if media is actively playing.
562 * @hide
563 */
564 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
565
566 /**
John Spurlock35134602014-07-24 18:10:48 -0400567 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
568 * @hide
569 */
570 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
571
572 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500573 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
574 * @hide
575 */
576 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
577
John Spurlockb94f2d62015-03-17 14:11:57 -0400578 /**
579 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900580 * This flag can be used in the places in order to denote (or check) that a volume adjustment
581 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400582 * @hide
583 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900584 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900585 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400586
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900587 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100588 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200589 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100590 ENCODED_SURROUND_OUTPUT_AUTO,
591 ENCODED_SURROUND_OUTPUT_NEVER,
592 ENCODED_SURROUND_OUTPUT_ALWAYS,
593 ENCODED_SURROUND_OUTPUT_MANUAL
594 })
595 @Retention(RetentionPolicy.SOURCE)
596 public @interface EncodedSurroundOutputMode {}
597
598 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200599 * The mode for surround sound formats is unknown.
600 */
601 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
602
603 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100604 * The surround sound formats are available for use if they are detected. This is the default
605 * mode.
606 */
607 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
608
609 /**
610 * The surround sound formats are NEVER available, even if they are detected by the hardware.
611 * Those formats will not be reported.
612 */
613 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
614
615 /**
616 * The surround sound formats are ALWAYS available, even if they are not detected by the
617 * hardware. Those formats will be reported as part of the HDMI output capability.
618 * Applications are then free to use either PCM or encoded output.
619 */
620 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
621
622 /**
623 * Surround sound formats are available according to the choice of user, even if they are not
624 * detected by the hardware. Those formats will be reported as part of the HDMI output
625 * capability. Applications are then free to use either PCM or encoded output.
626 */
627 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
628
629 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900630 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900631 FLAG_SHOW_UI,
632 FLAG_ALLOW_RINGER_MODES,
633 FLAG_PLAY_SOUND,
634 FLAG_REMOVE_SOUND_AND_VIBRATE,
635 FLAG_VIBRATE,
636 FLAG_FIXED_VOLUME,
637 FLAG_BLUETOOTH_ABS_VOLUME,
638 FLAG_SHOW_SILENT_HINT,
639 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
640 FLAG_ACTIVE_MEDIA_ONLY,
641 FLAG_SHOW_UI_WARNINGS,
642 FLAG_SHOW_VIBRATE_HINT,
643 FLAG_FROM_KEY,
644 })
645 @Retention(RetentionPolicy.SOURCE)
646 public @interface Flags {}
647
Hyundo Moonca0080d2018-12-26 16:16:55 +0900648 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
649 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
650
651 static {
652 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
653 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
654 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
655 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
656 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
657 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
658 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
659 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
660 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
661 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
662 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
663 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
664 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
665 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500666
667 /** @hide */
668 public static String flagsToString(int flags) {
669 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900670 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
671 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500672 if ((flags & flag) != 0) {
673 if (sb.length() > 0) {
674 sb.append(',');
675 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900676 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500677 flags &= ~flag;
678 }
679 }
680 if (flags != 0) {
681 if (sb.length() > 0) {
682 sb.append(',');
683 }
684 sb.append(flags);
685 }
686 return sb.toString();
687 }
688
689 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 * Ringer mode that will be silent and will not vibrate. (This overrides the
691 * vibrate setting.)
692 *
693 * @see #setRingerMode(int)
694 * @see #getRingerMode()
695 */
696 public static final int RINGER_MODE_SILENT = 0;
697
698 /**
699 * Ringer mode that will be silent and will vibrate. (This will cause the
700 * phone ringer to always vibrate, but the notification vibrate to only
701 * vibrate if set.)
702 *
703 * @see #setRingerMode(int)
704 * @see #getRingerMode()
705 */
706 public static final int RINGER_MODE_VIBRATE = 1;
707
708 /**
709 * Ringer mode that may be audible and may vibrate. It will be audible if
710 * the volume before changing out of this mode was audible. It will vibrate
711 * if the vibrate setting is on.
712 *
713 * @see #setRingerMode(int)
714 * @see #getRingerMode()
715 */
716 public static final int RINGER_MODE_NORMAL = 2;
717
John Spurlock97559372014-10-24 16:27:36 -0400718 /**
719 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
720 * @hide
721 */
722 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 /**
725 * Vibrate type that corresponds to the ringer.
726 *
727 * @see #setVibrateSetting(int, int)
728 * @see #getVibrateSetting(int)
729 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700730 * @deprecated Applications should maintain their own vibrate policy based on
731 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 */
733 public static final int VIBRATE_TYPE_RINGER = 0;
734
735 /**
736 * Vibrate type that corresponds to notifications.
737 *
738 * @see #setVibrateSetting(int, int)
739 * @see #getVibrateSetting(int)
740 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700741 * @deprecated Applications should maintain their own vibrate policy based on
742 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 */
744 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
745
746 /**
747 * Vibrate setting that suggests to never vibrate.
748 *
749 * @see #setVibrateSetting(int, int)
750 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700751 * @deprecated Applications should maintain their own vibrate policy based on
752 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 */
754 public static final int VIBRATE_SETTING_OFF = 0;
755
756 /**
757 * Vibrate setting that suggests to vibrate when possible.
758 *
759 * @see #setVibrateSetting(int, int)
760 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700761 * @deprecated Applications should maintain their own vibrate policy based on
762 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 */
764 public static final int VIBRATE_SETTING_ON = 1;
765
766 /**
767 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
768 * mode.
769 *
770 * @see #setVibrateSetting(int, int)
771 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700772 * @deprecated Applications should maintain their own vibrate policy based on
773 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 */
775 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
776
777 /**
778 * Suggests using the default stream type. This may not be used in all
779 * places a stream type is needed.
780 */
781 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
782
783 private static IAudioService sService;
784
785 /**
786 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800787 * For test purposes only, will throw NPE with some methods that require a Context.
788 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000789 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800790 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800791 }
792
793 /**
794 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100796 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700798 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 }
800
Marco Nelissen29f16932015-04-17 09:50:56 -0700801 private Context getContext() {
802 if (mApplicationContext == null) {
803 setContext(mOriginalContext);
804 }
805 if (mApplicationContext != null) {
806 return mApplicationContext;
807 }
808 return mOriginalContext;
809 }
810
811 private void setContext(Context context) {
812 mApplicationContext = context.getApplicationContext();
813 if (mApplicationContext != null) {
814 mOriginalContext = null;
815 } else {
816 mOriginalContext = context;
817 }
jiabin0f3339c2021-07-09 11:50:07 -0700818 sContext = new WeakReference<>(context);
Marco Nelissen29f16932015-04-17 09:50:56 -0700819 }
820
Mathew Inwood31a792a2018-08-17 08:54:26 +0100821 @UnsupportedAppUsage
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -0700822 static IAudioService getService()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 {
824 if (sService != null) {
825 return sService;
826 }
827 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
828 sService = IAudioService.Stub.asInterface(b);
829 return sService;
830 }
831
832 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700833 * Sends a simulated key event for a media button.
834 * To simulate a key press, you must first send a KeyEvent built with a
835 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
836 * action.
837 * <p>The key event will be sent to the current media key event consumer which registered with
838 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
839 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
840 * {@link KeyEvent#KEYCODE_MUTE},
841 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
842 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
843 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
844 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
845 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
846 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
847 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
848 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
849 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
850 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
851 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
852 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
853 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700854 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700855 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700856 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700857 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700858 }
859
860 /**
861 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700862 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800863 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700864 /*
865 * If the user hits another key within the play sound delay, then
866 * cancel the sound
867 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800868 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700869 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
870 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500871 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700872 /*
873 * The user has hit another key during the delay (e.g., 300ms)
874 * since the last volume key up, so cancel any sounds.
875 */
John Spurlockee5ad722015-03-03 16:17:21 -0500876 adjustSuggestedStreamVolume(ADJUST_SAME,
877 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700878 }
879 }
880
881 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700882 * Indicates if the device implements a fixed volume policy.
883 * <p>Some devices may not have volume control and may operate at a fixed volume,
884 * and may not enable muting or changing the volume of audio streams.
885 * This method will return true on such devices.
886 * <p>The following APIs have no effect when volume is fixed:
887 * <ul>
888 * <li> {@link #adjustVolume(int, int)}
889 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
890 * <li> {@link #adjustStreamVolume(int, int, int)}
891 * <li> {@link #setStreamVolume(int, int, int)}
892 * <li> {@link #setRingerMode(int)}
893 * <li> {@link #setStreamSolo(int, boolean)}
894 * <li> {@link #setStreamMute(int, boolean)}
895 * </ul>
896 */
897 public boolean isVolumeFixed() {
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700898 boolean res = false;
899 try {
900 res = getService().isVolumeFixed();
901 } catch (RemoteException e) {
902 Log.e(TAG, "Error querying isVolumeFixed", e);
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700903 }
Jean-Michel Trivi547d2632021-10-26 15:40:58 -0700904 return res;
Eric Laurentba207e72014-05-15 17:08:16 -0700905 }
906
907 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700909 * <p>
910 * This method should only be used by applications that replace the platform-wide
911 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700912 * <p>This method has no effect if the device implements a fixed volume policy
913 * as indicated by {@link #isVolumeFixed()}.
914 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
915 * unless the app has been granted Do Not Disturb Access.
916 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 *
918 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800919 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
920 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 * @param direction The direction to adjust the volume. One of
922 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
923 * {@link #ADJUST_SAME}.
924 * @param flags One or more flags.
925 * @see #adjustVolume(int, int)
926 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700927 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
928 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 */
930 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700931 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 try {
John Wu4f7e5102021-06-22 17:29:11 +0000933 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
934 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700936 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
938 }
939
940 /**
941 * Adjusts the volume of the most relevant stream. For example, if a call is
942 * active, it will have the highest priority regardless of if the in-call
943 * screen is showing. Another example, if music is playing in the background
944 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700945 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800946 * This method should only be used by applications that replace the
947 * platform-wide management of audio settings or the main telephony
948 * application.
949 * <p>
950 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700951 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800952 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800954 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
955 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
956 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 * @param flags One or more flags.
958 * @see #adjustSuggestedStreamVolume(int, int, int)
959 * @see #adjustStreamVolume(int, int, int)
960 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700961 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 */
963 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700964 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500965 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 }
967
968 /**
969 * Adjusts the volume of the most relevant stream, or the given fallback
970 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700971 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800972 * This method should only be used by applications that replace the
973 * platform-wide management of audio settings or the main telephony
974 * application.
975 * <p>
976 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700977 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800978 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800980 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
981 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
982 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -0800984 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
985 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 * @param flags One or more flags.
987 * @see #adjustVolume(int, int)
988 * @see #adjustStreamVolume(int, int, int)
989 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700990 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 */
992 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700993 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500994 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400995 }
996
John Spurlockee5ad722015-03-03 16:17:21 -0500997 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100998 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -0700999 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001000 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001001 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001002 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001003 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001004 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001005 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001006 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008 }
1009
1010 /**
1011 * Returns the current ringtone mode.
1012 *
1013 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1014 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1015 * @see #setRingerMode(int)
1016 */
1017 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001018 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001020 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001022 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024 }
1025
1026 /**
Lais Andrade724d0cd2021-11-03 19:46:21 +00001027 * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1028 *
1029 * @return true if the incoming phone call ringtone is configured to gradually increase its
1030 * volume, false otherwise.
1031 */
1032 public boolean isRampingRingerEnabled() {
1033 return Settings.System.getInt(getContext().getContentResolver(),
1034 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1035 }
1036
1037 /**
1038 * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1039 *
1040 * @see #isRampingRingerEnabled()
1041 * @hide
1042 */
1043 @TestApi
1044 public void setRampingRingerEnabled(boolean enabled) {
1045 Settings.System.putInt(getContext().getContentResolver(),
1046 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1047 }
1048
1049 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001050 * Checks valid ringer mode values.
1051 *
1052 * @return true if the ringer mode indicated is valid, false otherwise.
1053 *
1054 * @see #setRingerMode(int)
1055 * @hide
1056 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001057 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001058 public static boolean isValidRingerMode(int ringerMode) {
1059 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1060 return false;
1061 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001062 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001063 try {
1064 return service.isValidRingerMode(ringerMode);
1065 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001066 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001067 }
Eric Laurent72668b22011-07-19 16:04:27 -07001068 }
1069
1070 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 * Returns the maximum volume index for a particular stream.
1072 *
1073 * @param streamType The stream type whose maximum volume index is returned.
1074 * @return The maximum valid volume index for the stream.
1075 * @see #getStreamVolume(int)
1076 */
1077 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001078 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001080 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001082 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084 }
1085
1086 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001087 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001088 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1089 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1090 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1091 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1092 * @return The minimum valid volume index for the stream.
1093 * @see #getStreamVolume(int)
1094 */
1095 public int getStreamMinVolume(int streamType) {
1096 if (!isPublicStreamType(streamType)) {
1097 throw new IllegalArgumentException("Invalid stream type " + streamType);
1098 }
1099 return getStreamMinVolumeInt(streamType);
1100 }
1101
1102 /**
1103 * @hide
1104 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001105 * @param streamType The stream type whose minimum volume index is returned.
1106 * @return The minimum valid volume index for the stream.
1107 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001108 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001109 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001110 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001111 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001112 try {
1113 return service.getStreamMinVolume(streamType);
1114 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001115 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001116 }
1117 }
1118
1119 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 * Returns the current volume index for a particular stream.
1121 *
1122 * @param streamType The stream type whose volume index is returned.
1123 * @return The current volume index for the stream.
1124 * @see #getStreamMaxVolume(int)
1125 * @see #setStreamVolume(int, int, int)
1126 */
1127 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001128 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001130 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001132 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 }
1134 }
1135
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001136 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1137 private static final float VOLUME_MIN_DB = -758.0f;
1138
1139 /** @hide */
1140 @IntDef(flag = false, prefix = "STREAM", value = {
1141 STREAM_VOICE_CALL,
1142 STREAM_SYSTEM,
1143 STREAM_RING,
1144 STREAM_MUSIC,
1145 STREAM_ALARM,
1146 STREAM_NOTIFICATION,
1147 STREAM_DTMF,
1148 STREAM_ACCESSIBILITY }
1149 )
1150 @Retention(RetentionPolicy.SOURCE)
1151 public @interface PublicStreamTypes {}
1152
1153 /**
1154 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1155 * the given type of audio output device.
1156 * @param streamType stream type for which the volume is queried.
1157 * @param index the volume index for which the volume is queried. The index value must be
1158 * between the minimum and maximum index values for the given stream type (see
1159 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1160 * @param deviceType the type of audio output device for which volume is queried.
1161 * @return a volume expressed in dB.
1162 * A negative value indicates the audio signal is attenuated. A typical maximum value
1163 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1164 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1165 */
1166 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1167 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1168 if (!isPublicStreamType(streamType)) {
1169 throw new IllegalArgumentException("Invalid stream type " + streamType);
1170 }
1171 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1172 throw new IllegalArgumentException("Invalid stream volume index " + index);
1173 }
1174 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1175 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1176 }
1177 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1178 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1179 if (gain <= VOLUME_MIN_DB) {
1180 return Float.NEGATIVE_INFINITY;
1181 } else {
1182 return gain;
1183 }
1184 }
1185
1186 private static boolean isPublicStreamType(int streamType) {
1187 switch (streamType) {
1188 case STREAM_VOICE_CALL:
1189 case STREAM_SYSTEM:
1190 case STREAM_RING:
1191 case STREAM_MUSIC:
1192 case STREAM_ALARM:
1193 case STREAM_NOTIFICATION:
1194 case STREAM_DTMF:
1195 case STREAM_ACCESSIBILITY:
1196 return true;
1197 default:
1198 return false;
1199 }
1200 }
1201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001203 * Get last audible volume before stream was muted.
1204 *
1205 * @hide
1206 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001207 @UnsupportedAppUsage
Eric Laurent25101b02011-02-02 09:33:30 -08001208 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001209 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001210 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001211 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001212 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001213 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001214 }
1215 }
1216
1217 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001218 * Get the stream type whose volume is driving the UI sounds volume.
1219 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001220 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001221 * @hide
1222 */
John Spurlockee5ad722015-03-03 16:17:21 -05001223 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001224 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001225 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001226 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001227 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001228 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001229 }
1230 }
1231
1232 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 * Sets the ringer mode.
1234 * <p>
1235 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1236 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1237 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001238 * <p>This method has no effect if the device implements a fixed volume policy
1239 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001240 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1241 * unless the app has been granted Do Not Disturb Access.
1242 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1244 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1245 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001246 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 */
1248 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001249 if (!isValidRingerMode(ringerMode)) {
1250 return;
1251 }
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 {
Marco Nelissen29f16932015-04-17 09:50:56 -07001254 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001256 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 }
1258 }
1259
1260 /**
1261 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001262 * <p>This method has no effect if the device implements a fixed volume policy
1263 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001264 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1265 * the app has been granted Do Not Disturb Access.
1266 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 * @param streamType The stream whose volume index should be set.
1268 * @param index The volume index to set. See
1269 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1270 * @param flags One or more flags.
1271 * @see #getStreamMaxVolume(int)
1272 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001273 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001274 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1275 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 */
1277 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001278 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 try {
John Wu4f7e5102021-06-22 17:29:11 +00001280 service.setStreamVolumeWithAttribution(streamType, index, flags,
1281 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001283 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 }
1285 }
1286
1287 /**
François Gaffie9c362102018-09-21 17:43:52 +02001288 * Sets the volume index for a particular {@link AudioAttributes}.
1289 * @param attr The {@link AudioAttributes} whose volume index should be set.
1290 * @param index The volume index to set. See
1291 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1292 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1293 * @param flags One or more flags.
1294 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1295 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1296 * @see #isVolumeFixed()
1297 * @hide
1298 */
1299 @SystemApi
1300 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1301 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1302 Preconditions.checkNotNull(attr, "attr must not be null");
1303 final IAudioService service = getService();
1304 try {
1305 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001306 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001307 } catch (RemoteException e) {
1308 throw e.rethrowFromSystemServer();
1309 }
1310 }
1311
1312 /**
1313 * Returns the current volume index for a particular {@link AudioAttributes}.
1314 *
1315 * @param attr The {@link AudioAttributes} whose volume index is returned.
1316 * @return The current volume index for the stream.
1317 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1318 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1319 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1320 * @hide
1321 */
1322 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001323 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001324 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1325 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1326 Preconditions.checkNotNull(attr, "attr must not be null");
1327 final IAudioService service = getService();
1328 try {
1329 return service.getVolumeIndexForAttributes(attr);
1330 } catch (RemoteException e) {
1331 throw e.rethrowFromSystemServer();
1332 }
1333 }
1334
1335 /**
1336 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1337 *
1338 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1339 * @return The maximum valid volume index for the {@link AudioAttributes}.
1340 * @see #getVolumeIndexForAttributes(AudioAttributes)
1341 * @hide
1342 */
1343 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001344 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001345 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1346 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1347 Preconditions.checkNotNull(attr, "attr must not be null");
1348 final IAudioService service = getService();
1349 try {
1350 return service.getMaxVolumeIndexForAttributes(attr);
1351 } catch (RemoteException e) {
1352 throw e.rethrowFromSystemServer();
1353 }
1354 }
1355
1356 /**
1357 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1358 *
1359 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1360 * @return The minimum valid volume index for the {@link AudioAttributes}.
1361 * @see #getVolumeIndexForAttributes(AudioAttributes)
1362 * @hide
1363 */
1364 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001365 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001366 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1367 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1368 Preconditions.checkNotNull(attr, "attr must not be null");
1369 final IAudioService service = getService();
1370 try {
1371 return service.getMinVolumeIndexForAttributes(attr);
1372 } catch (RemoteException e) {
1373 throw e.rethrowFromSystemServer();
1374 }
1375 }
1376
1377 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001378 * Set the system usages to be supported on this device.
1379 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1380 * @hide
1381 */
1382 @SystemApi
1383 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1384 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1385 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1386 final IAudioService service = getService();
1387 try {
1388 service.setSupportedSystemUsages(systemUsages);
1389 } catch (RemoteException e) {
1390 throw e.rethrowFromSystemServer();
1391 }
1392 }
1393
1394 /**
1395 * Get the system usages supported on this device.
1396 * @return array of supported system usages {@link AttributeSystemUsage}
1397 * @hide
1398 */
1399 @SystemApi
1400 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1401 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1402 final IAudioService service = getService();
1403 try {
1404 return service.getSupportedSystemUsages();
1405 } catch (RemoteException e) {
1406 throw e.rethrowFromSystemServer();
1407 }
1408 }
1409
1410 /**
RoboErik4197cb62015-01-21 15:45:32 -08001411 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001413 * Do not use. This method has been deprecated and is now a no-op.
1414 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 *
1416 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001417 * @param state The required solo state: true for solo ON, false for solo
1418 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001419 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001420 * @deprecated Do not use. If you need exclusive audio playback use
1421 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 */
RoboErik4197cb62015-01-21 15:45:32 -08001423 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001425 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 }
1427
1428 /**
1429 * Mute or unmute an audio stream.
1430 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001431 * This method should only be used by applications that replace the
1432 * platform-wide management of audio settings or the main telephony
1433 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001435 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001436 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001437 * <p>
1438 * This method was deprecated in API level 22. Prior to API level 22 this
1439 * method had significantly different behavior and should be used carefully.
1440 * The following applies only to pre-22 platforms:
1441 * <ul>
1442 * <li>The mute command is protected against client process death: if a
1443 * process with an active mute request on a stream dies, this stream will be
1444 * unmuted automatically.</li>
1445 * <li>The mute requests for a given stream are cumulative: the AudioManager
1446 * can receive several mute requests from one or more clients and the stream
1447 * will be unmuted only when the same number of unmute requests are
1448 * received.</li>
1449 * <li>For a better user experience, applications MUST unmute a muted stream
1450 * in onPause() and mute is again in onResume() if appropriate.</li>
1451 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 *
1453 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001454 * @param state The required mute state: true for mute ON, false for mute
1455 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001456 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001457 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1458 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 */
RoboErik4197cb62015-01-21 15:45:32 -08001460 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001462 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1463 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1464 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1465 adjustSuggestedStreamVolume(direction, streamType, 0);
1466 } else {
1467 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 }
1469 }
1470
1471 /**
RoboErik4197cb62015-01-21 15:45:32 -08001472 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001473 *
RoboErik4197cb62015-01-21 15:45:32 -08001474 * @param streamType The stream to get mute state for.
1475 * @return The mute state for the given stream.
1476 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001477 */
1478 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001479 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001480 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001481 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001482 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001483 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001484 }
1485 }
1486
1487 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001488 * get master mute state.
1489 *
1490 * @hide
1491 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001492 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001493 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001494 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001495 try {
1496 return service.isMasterMute();
1497 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001498 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001499 }
1500 }
1501
1502 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001503 * forces the stream controlled by hard volume keys
1504 * specifying streamType == -1 releases control to the
1505 * logic.
1506 *
1507 * @hide
1508 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001509 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001510 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001511 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001512 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001513 try {
1514 service.forceVolumeControlStream(streamType, mICallBack);
1515 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001516 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001517 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001518 }
1519
1520 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 * Returns whether a particular type should vibrate according to user
1522 * settings and the current ringer mode.
1523 * <p>
1524 * This shouldn't be needed by most clients that use notifications to
1525 * vibrate. The notification manager will not vibrate if the policy doesn't
1526 * allow it, so the client should always set a vibrate pattern and let the
1527 * notification manager control whether or not to actually vibrate.
1528 *
1529 * @param vibrateType The type of vibrate. One of
1530 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1531 * {@link #VIBRATE_TYPE_RINGER}.
1532 * @return Whether the type should vibrate at the instant this method is
1533 * called.
1534 * @see #setVibrateSetting(int, int)
1535 * @see #getVibrateSetting(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 boolean shouldVibrate(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.shouldVibrate(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 * Returns whether the user's vibrate setting for a vibrate type.
1550 * <p>
1551 * This shouldn't be needed by most clients that want to vibrate, instead
1552 * see {@link #shouldVibrate(int)}.
1553 *
1554 * @param vibrateType The type of vibrate. One of
1555 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1556 * {@link #VIBRATE_TYPE_RINGER}.
1557 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1558 * {@link #VIBRATE_SETTING_OFF}, or
1559 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1560 * @see #setVibrateSetting(int, int)
1561 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001562 * @deprecated Applications should maintain their own vibrate policy based on
1563 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 */
1565 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001566 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 try {
1568 return service.getVibrateSetting(vibrateType);
1569 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001570 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 }
1572 }
1573
1574 /**
1575 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001576 * <p>
1577 * This method should only be used by applications that replace the platform-wide
1578 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 *
1580 * @param vibrateType The type of vibrate. One of
1581 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1582 * {@link #VIBRATE_TYPE_RINGER}.
1583 * @param vibrateSetting The vibrate setting, one of
1584 * {@link #VIBRATE_SETTING_ON},
1585 * {@link #VIBRATE_SETTING_OFF}, or
1586 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1587 * @see #getVibrateSetting(int)
1588 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001589 * @deprecated Applications should maintain their own vibrate policy based on
1590 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 */
1592 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001593 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 try {
1595 service.setVibrateSetting(vibrateType, vibrateSetting);
1596 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001597 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 }
1599 }
1600
1601 /**
1602 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001603 * <p>
1604 * This method should only be used by applications that replace the platform-wide
1605 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 *
1607 * @param on set <var>true</var> to turn on speakerphone;
1608 * <var>false</var> to turn it off
1609 */
1610 public void setSpeakerphoneOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001611 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001612 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001613 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001614 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001615 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001616 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 }
1618
1619 /**
1620 * Checks whether the speakerphone is on or off.
1621 *
1622 * @return true if speakerphone is on, false if it's off
1623 */
1624 public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001625 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001626 try {
1627 return service.isSpeakerphoneOn();
1628 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001629 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 }
1632
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001633 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001634 * 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 -07001635 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001636 *
1637 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1638 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001639 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001640 * <ul>
1641 * <li> for each track independently, see
1642 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1643 * <li> application-wide at runtime, with this method </li>
1644 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1645 * manifest. </li>
1646 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001647 * The most restrictive policy is always applied.
1648 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001649 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001650 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001651 *
1652 * @param capturePolicy one of
1653 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1654 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1655 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001656 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001657 */
1658 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001659 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001660 final IAudioService service = getService();
1661 try {
1662 int result = service.setAllowedCapturePolicy(capturePolicy);
1663 if (result != AudioSystem.AUDIO_STATUS_OK) {
1664 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1665 return;
1666 }
1667 } catch (RemoteException e) {
1668 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001669 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001670 }
1671
Kevin Rocard019f60d2019-04-09 16:25:26 -07001672 /**
1673 * Return the capture policy.
1674 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1675 * the default if it was not called.
1676 */
1677 @AudioAttributes.CapturePolicy
1678 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001679 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1680 try {
1681 result = getService().getAllowedCapturePolicy();
1682 } catch (RemoteException e) {
1683 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1684 }
1685 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001686 }
1687
Eric Laurent3def1ee2010-03-17 23:26:26 -07001688 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001689 // Audio Product Strategy routing
1690
1691 /**
1692 * @hide
1693 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1694 * this audio strategy. Note that the device may not be available at the time the preferred
1695 * device is set, but it will be used once made available.
1696 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1697 * this preference for this strategy.</p>
1698 * @param strategy the audio strategy whose routing will be affected
1699 * @param device the audio device to route to when available
1700 * @return true if the operation was successful, false otherwise
1701 */
1702 @SystemApi
1703 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1704 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001705 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001706 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001707 }
1708
1709 /**
1710 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001711 * Removes the preferred audio device(s) previously set with
1712 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1713 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001714 * @param strategy the audio strategy whose routing will be affected
1715 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1716 * device set for example)
1717 */
1718 @SystemApi
1719 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1720 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1721 Objects.requireNonNull(strategy);
1722 try {
1723 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001724 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001725 return status == AudioSystem.SUCCESS;
1726 } catch (RemoteException e) {
1727 throw e.rethrowFromSystemServer();
1728 }
1729 }
1730
1731 /**
1732 * @hide
1733 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001734 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1735 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1736 * @param strategy the strategy to query
1737 * @return the preferred device for that strategy, if multiple devices are set as preferred
1738 * devices, the first one in the list will be returned. Null will be returned if none was
1739 * ever set or if the strategy is invalid
1740 */
1741 @SystemApi
1742 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1743 @Nullable
1744 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1745 @NonNull AudioProductStrategy strategy) {
1746 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1747 return devices.isEmpty() ? null : devices.get(0);
1748 }
1749
1750 /**
1751 * @hide
1752 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1753 * this audio strategy. Note that the devices may not be available at the time the preferred
1754 * devices is set, but it will be used once made available.
1755 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1756 * this preference for this strategy.</p>
1757 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1758 * devices used simultaneously to output the same audio signal.
1759 * @param strategy the audio strategy whose routing will be affected
1760 * @param devices a non-empty list of the audio devices to route to when available
1761 * @return true if the operation was successful, false otherwise
1762 */
1763 @SystemApi
1764 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1765 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1766 @NonNull List<AudioDeviceAttributes> devices) {
1767 Objects.requireNonNull(strategy);
1768 Objects.requireNonNull(devices);
1769 if (devices.isEmpty()) {
1770 throw new IllegalArgumentException(
1771 "Tried to set preferred devices for strategy with a empty list");
1772 }
1773 for (AudioDeviceAttributes device : devices) {
1774 Objects.requireNonNull(device);
1775 }
1776 try {
1777 final int status =
1778 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1779 return status == AudioSystem.SUCCESS;
1780 } catch (RemoteException e) {
1781 throw e.rethrowFromSystemServer();
1782 }
1783 }
1784
1785 /**
1786 * @hide
1787 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001788 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001789 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001790 * @param strategy the strategy to query
1791 * @return the preferred device for that strategy, or null if none was ever set or if the
1792 * strategy is invalid
1793 */
1794 @SystemApi
1795 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001796 @NonNull
1797 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001798 @NonNull AudioProductStrategy strategy) {
1799 Objects.requireNonNull(strategy);
1800 try {
jiabinf40141d2020-08-07 17:27:48 -07001801 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001802 } catch (RemoteException e) {
1803 throw e.rethrowFromSystemServer();
1804 }
1805 }
1806
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001807 /**
1808 * @hide
1809 * Interface to be notified of changes in the preferred audio device set for a given audio
1810 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001811 * <p>Note that this listener will only be invoked whenever
1812 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001813 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001814 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1815 * preferred device. It will not be invoked directly after registration with
1816 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1817 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001818 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001819 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1820 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001821 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001822 */
1823 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001824 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001825 public interface OnPreferredDeviceForStrategyChangedListener {
1826 /**
1827 * Called on the listener to indicate that the preferred audio device for the given
1828 * strategy has changed.
1829 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1830 * @param device <code>null</code> if the preferred device was removed, or the newly set
1831 * preferred audio device
1832 */
1833 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001834 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001835 }
1836
1837 /**
1838 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001839 * Interface to be notified of changes in the preferred audio devices set for a given audio
1840 * strategy.
1841 * <p>Note that this listener will only be invoked whenever
1842 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1843 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1844 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1845 * preferred device(s). It will not be invoked directly after registration with
1846 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1847 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1848 * to indicate which strategies had preferred devices at the time of registration.</p>
1849 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1850 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1851 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1852 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
1853 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1854 */
1855 @SystemApi
1856 public interface OnPreferredDevicesForStrategyChangedListener {
1857 /**
1858 * Called on the listener to indicate that the preferred audio devices for the given
1859 * strategy has changed.
1860 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1861 * @param devices a list of newly set preferred audio devices
1862 */
1863 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1864 @NonNull List<AudioDeviceAttributes> devices);
1865 }
1866
1867 /**
1868 * @hide
1869 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1870 * @param executor
1871 * @param listener
1872 * @throws SecurityException if the caller doesn't hold the required permission
1873 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1874 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1875 */
1876 @SystemApi
1877 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1878 @Deprecated
1879 public void addOnPreferredDeviceForStrategyChangedListener(
1880 @NonNull @CallbackExecutor Executor executor,
1881 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
1882 throws SecurityException {
1883 // No-op, the method is deprecated.
1884 }
1885
1886 /**
1887 * @hide
1888 * Removes a previously added listener of changes to the strategy-preferred audio device.
1889 * @param listener
1890 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
1891 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1892 */
1893 @SystemApi
1894 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1895 @Deprecated
1896 public void removeOnPreferredDeviceForStrategyChangedListener(
1897 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
1898 // No-op, the method is deprecated.
1899 }
1900
1901 /**
1902 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001903 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1904 * @param executor
1905 * @param listener
1906 * @throws SecurityException if the caller doesn't hold the required permission
1907 */
1908 @SystemApi
1909 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001910 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001911 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07001912 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001913 throws SecurityException {
1914 Objects.requireNonNull(executor);
1915 Objects.requireNonNull(listener);
1916 synchronized (mPrefDevListenerLock) {
1917 if (hasPrefDevListener(listener)) {
1918 throw new IllegalArgumentException(
jiabinf40141d2020-08-07 17:27:48 -07001919 "attempt to call addOnPreferredDevicesForStrategyChangedListener() "
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001920 + "on a previously registered listener");
1921 }
1922 // lazy initialization of the list of strategy-preferred device listener
1923 if (mPrefDevListeners == null) {
1924 mPrefDevListeners = new ArrayList<>();
1925 }
1926 final int oldCbCount = mPrefDevListeners.size();
1927 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor));
1928 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) {
1929 // register binder for callbacks
1930 if (mPrefDevDispatcherStub == null) {
jiabinf40141d2020-08-07 17:27:48 -07001931 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001932 }
1933 try {
jiabinf40141d2020-08-07 17:27:48 -07001934 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001935 } catch (RemoteException e) {
1936 throw e.rethrowFromSystemServer();
1937 }
1938 }
1939 }
1940 }
1941
1942 /**
1943 * @hide
1944 * Removes a previously added listener of changes to the strategy-preferred audio device.
1945 * @param listener
1946 */
1947 @SystemApi
1948 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001949 public void removeOnPreferredDevicesForStrategyChangedListener(
1950 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001951 Objects.requireNonNull(listener);
1952 synchronized (mPrefDevListenerLock) {
1953 if (!removePrefDevListener(listener)) {
1954 throw new IllegalArgumentException(
1955 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() "
1956 + "on an unregistered listener");
1957 }
1958 if (mPrefDevListeners.size() == 0) {
1959 // unregister binder for callbacks
1960 try {
jiabinf40141d2020-08-07 17:27:48 -07001961 getService().unregisterStrategyPreferredDevicesDispatcher(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001962 mPrefDevDispatcherStub);
1963 } catch (RemoteException e) {
1964 throw e.rethrowFromSystemServer();
1965 } finally {
1966 mPrefDevDispatcherStub = null;
1967 mPrefDevListeners = null;
1968 }
1969 }
1970 }
1971 }
1972
1973
1974 private final Object mPrefDevListenerLock = new Object();
1975 /**
1976 * List of listeners for preferred device for strategy and their associated Executor.
1977 * List is lazy-initialized on first registration
1978 */
1979 @GuardedBy("mPrefDevListenerLock")
1980 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners;
1981
1982 private static class PrefDevListenerInfo {
jiabinf40141d2020-08-07 17:27:48 -07001983 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001984 final @NonNull Executor mExecutor;
jiabinf40141d2020-08-07 17:27:48 -07001985 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001986 mListener = listener;
1987 mExecutor = exe;
1988 }
1989 }
1990
1991 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07001992 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001993
jiabinf40141d2020-08-07 17:27:48 -07001994 private final class StrategyPreferredDevicesDispatcherStub
1995 extends IStrategyPreferredDevicesDispatcher.Stub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001996
1997 @Override
jiabinf40141d2020-08-07 17:27:48 -07001998 public void dispatchPrefDevicesChanged(int strategyId,
1999 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002000 // make a shallow copy of listeners so callback is not executed under lock
2001 final ArrayList<PrefDevListenerInfo> prefDevListeners;
2002 synchronized (mPrefDevListenerLock) {
2003 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) {
2004 return;
2005 }
2006 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone();
2007 }
2008 final AudioProductStrategy strategy =
2009 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2010 final long ident = Binder.clearCallingIdentity();
2011 try {
2012 for (PrefDevListenerInfo info : prefDevListeners) {
2013 info.mExecutor.execute(() ->
jiabinf40141d2020-08-07 17:27:48 -07002014 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices));
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002015 }
2016 } finally {
2017 Binder.restoreCallingIdentity(ident);
2018 }
2019 }
2020 }
2021
2022 @GuardedBy("mPrefDevListenerLock")
2023 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo(
jiabinf40141d2020-08-07 17:27:48 -07002024 OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002025 if (mPrefDevListeners == null) {
2026 return null;
2027 }
2028 for (PrefDevListenerInfo info : mPrefDevListeners) {
2029 if (info.mListener == listener) {
2030 return info;
2031 }
2032 }
2033 return null;
2034 }
2035
2036 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002037 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002038 return getPrefDevListenerInfo(listener) != null;
2039 }
2040
2041 @GuardedBy("mPrefDevListenerLock")
2042 /**
2043 * @return true if the listener was removed from the list
2044 */
jiabinf40141d2020-08-07 17:27:48 -07002045 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002046 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener);
2047 if (infoToRemove != null) {
2048 mPrefDevListeners.remove(infoToRemove);
2049 return true;
2050 }
2051 return false;
2052 }
2053
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002054 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002055 // Audio Capture Preset routing
2056
2057 /**
2058 * @hide
2059 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2060 * this capture preset. Note that the device may not be available at the time the preferred
2061 * device is set, but it will be used once made available.
2062 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2063 * for this capture preset.</p>
2064 * @param capturePreset the audio capture preset whose routing will be affected
2065 * @param device the audio device to route to when available
2066 * @return true if the operation was successful, false otherwise
2067 */
2068 @SystemApi
2069 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002070 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002071 @NonNull AudioDeviceAttributes device) {
2072 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2073 }
2074
2075 /**
2076 * @hide
2077 * Remove all the preferred audio devices previously set
2078 * @param capturePreset the audio capture preset whose routing will be affected
2079 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2080 * device set for example)
2081 */
2082 @SystemApi
2083 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002084 public boolean clearPreferredDevicesForCapturePreset(
2085 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002086 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2087 return false;
2088 }
2089 try {
2090 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2091 return status == AudioSystem.SUCCESS;
2092 } catch (RemoteException e) {
2093 throw e.rethrowFromSystemServer();
2094 }
2095 }
2096
2097 /**
2098 * @hide
2099 * Return the preferred devices for an audio capture preset, previously set with
2100 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2101 * @param capturePreset the capture preset to query
2102 * @return a list that contains preferred devices for that capture preset.
2103 */
2104 @NonNull
2105 @SystemApi
2106 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002107 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2108 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002109 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2110 return new ArrayList<AudioDeviceAttributes>();
2111 }
2112 try {
2113 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2114 } catch (RemoteException e) {
2115 throw e.rethrowFromSystemServer();
2116 }
2117 }
2118
2119 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002120 @MediaRecorder.SystemSource int capturePreset,
2121 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002122 Objects.requireNonNull(devices);
2123 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2124 return false;
2125 }
2126 if (devices.size() != 1) {
2127 throw new IllegalArgumentException(
2128 "Only support setting one preferred devices for capture preset");
2129 }
2130 for (AudioDeviceAttributes device : devices) {
2131 Objects.requireNonNull(device);
2132 }
2133 try {
2134 final int status =
2135 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2136 return status == AudioSystem.SUCCESS;
2137 } catch (RemoteException e) {
2138 throw e.rethrowFromSystemServer();
2139 }
2140 }
2141
2142 /**
2143 * @hide
2144 * Interface to be notified of changes in the preferred audio devices set for a given capture
2145 * preset.
2146 * <p>Note that this listener will only be invoked whenever
2147 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2148 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2149 * preferred device. It will not be invoked directly after registration with
2150 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2151 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2152 * to indicate which strategies had preferred devices at the time of registration.</p>
2153 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2154 * @see #clearPreferredDevicesForCapturePreset(int)
2155 * @see #getPreferredDevicesForCapturePreset(int)
2156 */
2157 @SystemApi
2158 public interface OnPreferredDevicesForCapturePresetChangedListener {
2159 /**
2160 * Called on the listener to indicate that the preferred audio devices for the given
2161 * capture preset has changed.
2162 * @param capturePreset the capture preset whose preferred device changed
2163 * @param devices a list of newly set preferred audio devices
2164 */
2165 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002166 @MediaRecorder.SystemSource int capturePreset,
2167 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002168 }
2169
2170 /**
2171 * @hide
2172 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2173 * @param executor
2174 * @param listener
2175 * @throws SecurityException if the caller doesn't hold the required permission
2176 */
2177 @SystemApi
2178 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2179 public void addOnPreferredDevicesForCapturePresetChangedListener(
2180 @NonNull @CallbackExecutor Executor executor,
2181 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2182 throws SecurityException {
2183 Objects.requireNonNull(executor);
2184 Objects.requireNonNull(listener);
2185 int status = addOnDevRoleForCapturePresetChangedListener(
2186 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2187 if (status == AudioSystem.ERROR) {
2188 // This must not happen
2189 throw new RuntimeException("Unknown error happened");
2190 }
2191 if (status == AudioSystem.BAD_VALUE) {
2192 throw new IllegalArgumentException(
2193 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2194 + "on a previously registered listener");
2195 }
2196 }
2197
2198 /**
2199 * @hide
2200 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2201 * @param listener
2202 */
2203 @SystemApi
2204 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2205 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2206 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2207 Objects.requireNonNull(listener);
2208 int status = removeOnDevRoleForCapturePresetChangedListener(
2209 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2210 if (status == AudioSystem.ERROR) {
2211 // This must not happen
2212 throw new RuntimeException("Unknown error happened");
2213 }
2214 if (status == AudioSystem.BAD_VALUE) {
2215 throw new IllegalArgumentException(
2216 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2217 + "on an unregistered listener");
2218 }
2219 }
2220
2221 private <T> int addOnDevRoleForCapturePresetChangedListener(
2222 @NonNull @CallbackExecutor Executor executor,
2223 @NonNull T listener, int deviceRole) {
2224 Objects.requireNonNull(executor);
2225 Objects.requireNonNull(listener);
2226 DevRoleListeners<T> devRoleListeners =
2227 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2228 if (devRoleListeners == null) {
2229 return AudioSystem.ERROR;
2230 }
2231 synchronized (devRoleListeners.mDevRoleListenersLock) {
2232 if (devRoleListeners.hasDevRoleListener(listener)) {
2233 return AudioSystem.BAD_VALUE;
2234 }
2235 // lazy initialization of the list of device role listener
2236 if (devRoleListeners.mListenerInfos == null) {
2237 devRoleListeners.mListenerInfos = new ArrayList<>();
2238 }
2239 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2240 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2241 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2242 // register binder for callbacks
2243 synchronized (mDevRoleForCapturePresetListenersLock) {
2244 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2245 mDeviceRoleListenersStatus |= (1 << deviceRole);
2246 if (deviceRoleListenerStatus != 0) {
2247 // There are already device role changed listeners active.
2248 return AudioSystem.SUCCESS;
2249 }
2250 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2251 mDevicesRoleForCapturePresetDispatcherStub =
2252 new CapturePresetDevicesRoleDispatcherStub();
2253 }
2254 try {
2255 getService().registerCapturePresetDevicesRoleDispatcher(
2256 mDevicesRoleForCapturePresetDispatcherStub);
2257 } catch (RemoteException e) {
2258 throw e.rethrowFromSystemServer();
2259 }
2260 }
2261 }
2262 }
2263 return AudioSystem.SUCCESS;
2264 }
2265
2266 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2267 @NonNull T listener, int deviceRole) {
2268 Objects.requireNonNull(listener);
2269 DevRoleListeners<T> devRoleListeners =
2270 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2271 if (devRoleListeners == null) {
2272 return AudioSystem.ERROR;
2273 }
2274 synchronized (devRoleListeners.mDevRoleListenersLock) {
2275 if (!devRoleListeners.removeDevRoleListener(listener)) {
2276 return AudioSystem.BAD_VALUE;
2277 }
2278 if (devRoleListeners.mListenerInfos.size() == 0) {
2279 // unregister binder for callbacks
2280 synchronized (mDevRoleForCapturePresetListenersLock) {
2281 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2282 if (mDeviceRoleListenersStatus != 0) {
2283 // There are some other device role changed listeners active.
2284 return AudioSystem.SUCCESS;
2285 }
2286 try {
2287 getService().unregisterCapturePresetDevicesRoleDispatcher(
2288 mDevicesRoleForCapturePresetDispatcherStub);
2289 } catch (RemoteException e) {
2290 throw e.rethrowFromSystemServer();
2291 }
2292 }
2293 }
2294 }
2295 return AudioSystem.SUCCESS;
2296 }
2297
2298 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
2299 put(AudioSystem.DEVICE_ROLE_PREFERRED,
2300 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
2301 }};
2302
2303 private class DevRoleListenerInfo<T> {
2304 final @NonNull Executor mExecutor;
2305 final @NonNull T mListener;
2306 DevRoleListenerInfo(Executor executor, T listener) {
2307 mExecutor = executor;
2308 mListener = listener;
2309 }
2310 }
2311
2312 private class DevRoleListeners<T> {
2313 private final Object mDevRoleListenersLock = new Object();
2314 @GuardedBy("mDevRoleListenersLock")
2315 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2316
2317 @GuardedBy("mDevRoleListenersLock")
2318 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2319 if (mListenerInfos == null) {
2320 return null;
2321 }
2322 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2323 if (listenerInfo.mListener == listener) {
2324 return listenerInfo;
2325 }
2326 }
2327 return null;
2328 }
2329
2330 @GuardedBy("mDevRoleListenersLock")
2331 private boolean hasDevRoleListener(T listener) {
2332 return getDevRoleListenerInfo(listener) != null;
2333 }
2334
2335 @GuardedBy("mDevRoleListenersLock")
2336 private boolean removeDevRoleListener(T listener) {
2337 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2338 if (infoToRemove != null) {
2339 mListenerInfos.remove(infoToRemove);
2340 return true;
2341 }
2342 return false;
2343 }
2344 }
2345
2346 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2347 /**
2348 * Record if there is a listener added for device role change. If there is a listener added for
2349 * a specified device role change, the bit at position `1 << device_role` is set.
2350 */
2351 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2352 private int mDeviceRoleListenersStatus = 0;
2353 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2354 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2355
2356 private final class CapturePresetDevicesRoleDispatcherStub
2357 extends ICapturePresetDevicesRoleDispatcher.Stub {
2358
2359 @Override
2360 public void dispatchDevicesRoleChanged(
2361 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2362 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2363 if (listenersObj == null) {
2364 return;
2365 }
2366 switch (role) {
2367 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2368 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2369 listeners =
2370 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2371 listenersObj;
2372 final ArrayList<DevRoleListenerInfo<
2373 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2374 synchronized (listeners.mDevRoleListenersLock) {
2375 if (listeners.mListenerInfos.isEmpty()) {
2376 return;
2377 }
2378 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2379 OnPreferredDevicesForCapturePresetChangedListener>>)
2380 listeners.mListenerInfos.clone();
2381 }
2382 final long ident = Binder.clearCallingIdentity();
2383 try {
2384 for (DevRoleListenerInfo<
2385 OnPreferredDevicesForCapturePresetChangedListener> info :
2386 prefDevListeners) {
2387 info.mExecutor.execute(() ->
2388 info.mListener.onPreferredDevicesForCapturePresetChanged(
2389 capturePreset, devices));
2390 }
2391 } finally {
2392 Binder.restoreCallingIdentity(ident);
2393 }
2394 } break;
2395 default:
2396 break;
2397 }
2398 }
2399 }
2400
2401 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002402 // Offload query
2403 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002404 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002405 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2406 * is not competing with other software resources. In general, it is supported by dedicated
2407 * hardware, such as audio DSPs.
2408 * <p>Note that this query only provides information about the support of an audio format,
2409 * it does not indicate whether the resources necessary for the offloaded playback are
2410 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002411 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002412 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002413 * @return true if the given audio format can be offloaded.
2414 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002415 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2416 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002417 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002418 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002419 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002420 if (attributes == null) {
2421 throw new NullPointerException("Illegal null AudioAttributes");
2422 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002423 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2424 }
2425
2426 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2427 offload playback not supported */
2428 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2429 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2430 offload playback supported */
2431 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2432 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2433 offload playback supported with gapless transitions */
2434 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2435 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2436
2437 /** @hide */
2438 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2439 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2440 PLAYBACK_OFFLOAD_SUPPORTED,
2441 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2442 )
2443 @Retention(RetentionPolicy.SOURCE)
2444 public @interface AudioOffloadMode {}
2445
2446 /**
2447 * Returns whether offloaded playback of an audio format is supported on the device or not and
2448 * when supported whether gapless transitions are possible or not.
2449 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2450 * is not competing with other software resources. In general, it is supported by dedicated
2451 * hardware, such as audio DSPs.
2452 * <p>Note that this query only provides information about the support of an audio format,
2453 * it does not indicate whether the resources necessary for the offloaded playback are
2454 * available at that instant.
2455 * @param format the audio format (codec, sample rate, channels) being checked.
2456 * @param attributes the {@link AudioAttributes} to be used for playback
2457 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2458 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2459 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2460 * also supported.
2461 */
2462 @AudioOffloadMode
2463 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2464 @NonNull AudioAttributes attributes) {
2465 if (format == null) {
2466 throw new NullPointerException("Illegal null AudioFormat");
2467 }
2468 if (attributes == null) {
2469 throw new NullPointerException("Illegal null AudioAttributes");
2470 }
2471 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002472 }
2473
2474 //====================================================================
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002475 // Immersive audio
2476
2477 /**
2478 * Return a handle to the optional platform's {@link Spatializer}
Jean-Michel Trivi838913c2021-09-02 20:55:44 -07002479 * @return the {@code Spatializer} instance.
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002480 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2481 * on the platform
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002482 */
Jean-Michel Trivic5f69572021-09-14 10:46:55 -07002483 public @NonNull Spatializer getSpatializer() {
Jean-Michel Trivie9dd14e2021-07-12 11:10:18 -07002484 return new Spatializer(this);
2485 }
2486
2487 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002488 // Bluetooth SCO control
2489 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002490 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002491 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002492 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2493 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2494 *
2495 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002496 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002497 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002498 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002499 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2500 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2501 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002502
2503 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002504 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002505 * connection state has been updated.
2506 * <p>This intent has two extras:
2507 * <ul>
2508 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2509 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2510 * </ul>
2511 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2512 * <ul>
2513 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2514 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2515 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2516 * </ul>
2517 * @see #startBluetoothSco()
2518 */
2519 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2520 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2521 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2522
Eric Laurent3def1ee2010-03-17 23:26:26 -07002523 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002524 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2525 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002526 */
2527 public static final String EXTRA_SCO_AUDIO_STATE =
2528 "android.media.extra.SCO_AUDIO_STATE";
2529
2530 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002531 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2532 * bluetooth SCO connection state.
2533 */
2534 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2535 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2536
2537 /**
2538 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2539 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002540 */
2541 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2542 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002543 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2544 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002545 */
2546 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2547 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002548 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2549 * indicating that the SCO audio channel is being established
2550 */
2551 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2552 /**
2553 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002554 * there was an error trying to obtain the state
2555 */
2556 public static final int SCO_AUDIO_STATE_ERROR = -1;
2557
2558
2559 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002560 * Indicates if current platform supports use of SCO for off call use cases.
2561 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002562 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002563 * feature.
2564 * @return true if bluetooth SCO can be used for audio when not in call
2565 * false otherwise
2566 * @see #startBluetoothSco()
2567 */
2568 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002569 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002570 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2571 }
2572
2573 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002574 * Start bluetooth SCO audio connection.
2575 * <p>Requires Permission:
2576 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2577 * <p>This method can be used by applications wanting to send and received audio
2578 * to/from a bluetooth SCO headset while the phone is not in call.
2579 * <p>As the SCO connection establishment can take several seconds,
2580 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002581 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002582 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002583 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2584 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2585 * registration. If the state is already CONNECTED, no state change will be received via the
2586 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2587 * so that the connection stays active in case the current initiator stops the connection.
2588 * <p>Unless the connection is already active as described above, the state will always
2589 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2590 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2591 * <p>When finished with the SCO connection or if the establishment fails, the application must
2592 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002593 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2594 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002595 * <ul>
2596 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2597 * <li> the format must be mono </li>
2598 * <li> the sampling must be 16kHz or 8kHz </li>
2599 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002600 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002601 * <ul>
2602 * <li> the format must be mono </li>
2603 * <li> the sampling must be 8kHz </li>
2604 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002605 * <p>Note that the phone application always has the priority on the usage of the SCO
2606 * connection for telephony. If this method is called while the phone is in call
2607 * it will be ignored. Similarly, if a call is received or sent while an application
2608 * is using the SCO connection, the connection will be lost for the application and NOT
2609 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002610 * <p>NOTE: up to and including API version
2611 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2612 * voice call to the bluetooth headset.
2613 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2614 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002615 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002616 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurent3def1ee2010-03-17 23:26:26 -07002617 */
2618 public void startBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002619 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002620 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002621 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002622 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002623 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002624 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002625 }
2626 }
2627
2628 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002629 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002630 * Start bluetooth SCO audio connection in virtual call mode.
2631 * <p>Requires Permission:
2632 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2633 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2634 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2635 * virtual call mode.
2636 * Applications using voice input for search or commands should first try raw audio connection
2637 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2638 * failure.
2639 * @see #startBluetoothSco()
2640 * @see #stopBluetoothSco()
2641 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2642 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002643 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002644 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002645 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002646 try {
2647 service.startBluetoothScoVirtualCall(mICallBack);
2648 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002649 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002650 }
2651 }
2652
2653 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002654 * Stop bluetooth SCO audio connection.
2655 * <p>Requires Permission:
2656 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2657 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002658 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2659 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002660 * @see #startBluetoothSco()
2661 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002662 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002663 public void stopBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002664 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002665 try {
2666 service.stopBluetoothSco(mICallBack);
2667 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002668 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002669 }
2670 }
2671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002673 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002674 * <p>
2675 * This method should only be used by applications that replace the platform-wide
2676 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677 *
Eric Laurenta553c252009-07-17 12:17:14 -07002678 * @param on set <var>true</var> to use bluetooth SCO for communications;
2679 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 */
2681 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002682 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002683 try {
2684 service.setBluetoothScoOn(on);
2685 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002686 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 }
2689
2690 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002691 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002692 *
Eric Laurenta553c252009-07-17 12:17:14 -07002693 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 * false if otherwise
2695 */
2696 public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002697 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002698 try {
2699 return service.isBluetoothScoOn();
2700 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002701 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 }
2704
2705 /**
Eric Laurent242b3382012-06-15 11:48:50 -07002706 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2707 * headset; <var>false</var> disable A2DP audio
Eric Laurenta553c252009-07-17 12:17:14 -07002708 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 */
Eric Laurenta553c252009-07-17 12:17:14 -07002710 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 }
2712
2713 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002714 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002716 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002717 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002718 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 */
2720 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002721 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002722 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2723 return true;
2724 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2725 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2726 return true;
2727 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2728 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002729 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002730 }
Eric Laurent9656df22016-04-20 16:42:28 -07002731 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 }
2733
2734 /**
2735 * Sets audio routing to the wired headset on or off.
2736 *
2737 * @param on set <var>true</var> to route audio to/from wired
2738 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002739 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 */
Eric Laurenta553c252009-07-17 12:17:14 -07002741 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002742 }
2743
2744 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002745 * Checks whether a wired headset is connected or not.
2746 * <p>This is not a valid indication that audio playback is
2747 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002749 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002750 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002751 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752 */
2753 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002754 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002755 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002756 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002757 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2758 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2759 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002760 return false;
2761 } else {
2762 return true;
2763 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002764 }
2765
2766 /**
2767 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002768 * <p>
2769 * This method should only be used by applications that replace the platform-wide
2770 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002771 *
2772 * @param on set <var>true</var> to mute the microphone;
2773 * <var>false</var> to turn mute off
2774 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002775 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002776 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002777 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002778 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002779 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002780 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002781 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 }
2784
2785 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002786 * @hide
2787 * Sets the microphone from switch mute on or off.
2788 * <p>
2789 * This method should only be used by InputManager to notify
2790 * Audio Subsystem about Microphone Mute switch state.
2791 *
2792 * @param on set <var>true</var> to mute the microphone;
2793 * <var>false</var> to turn mute off
2794 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002795 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002796 public void setMicrophoneMuteFromSwitch(boolean on) {
2797 final IAudioService service = getService();
2798 try {
2799 service.setMicrophoneMuteFromSwitch(on);
2800 } catch (RemoteException e) {
2801 throw e.rethrowFromSystemServer();
2802 }
2803 }
2804
2805 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002806 * Checks whether the microphone mute is on or off.
2807 *
2808 * @return true if microphone is muted, false if it's not
2809 */
2810 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002811 final IAudioService service = getService();
2812 try {
2813 return service.isMicrophoneMuted();
2814 } catch (RemoteException e) {
2815 throw e.rethrowFromSystemServer();
2816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002817 }
2818
2819 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002820 * Broadcast Action: microphone muting state changed.
2821 *
2822 * You <em>cannot</em> receive this through components declared
2823 * in manifests, only by explicitly registering for it with
2824 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2825 * Context.registerReceiver()}.
2826 *
2827 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2828 * microphone is muted.
2829 */
2830 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2831 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2832 "android.media.action.MICROPHONE_MUTE_CHANGED";
2833
2834 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07002835 * Broadcast Action: speakerphone state changed.
2836 *
2837 * You <em>cannot</em> receive this through components declared
2838 * in manifests, only by explicitly registering for it with
2839 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2840 * Context.registerReceiver()}.
2841 *
2842 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2843 * speakerphone functionality is enabled or not.
2844 */
2845 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2846 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2847 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2848
2849 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002851 * <p>
2852 * The audio mode encompasses audio routing AND the behavior of
2853 * the telephony layer. Therefore this method should only be used by applications that
2854 * replace the platform-wide management of audio settings or the main telephony application.
2855 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2856 * application when it places a phone call, as it will cause signals from the radio layer
2857 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002858 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002859 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 * Informs the HAL about the current audio state so that
2861 * it can route the audio appropriately.
2862 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002863 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002864 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002865 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07002866 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002867 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002868 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 }
2870 }
2871
2872 /**
Eric Laurent1c3408f2021-11-09 12:09:54 +01002873 * This change id controls use of audio modes for call audio redirection.
2874 * @hide
2875 */
2876 @ChangeId
2877 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
2878 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
2879
2880 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002881 * Returns the current audio mode.
2882 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002883 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002885 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002887 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002888 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002889 int mode = service.getMode();
2890 int sdk;
2891 try {
2892 sdk = getContext().getApplicationInfo().targetSdkVersion;
2893 } catch (NullPointerException e) {
2894 // some tests don't have a Context
2895 sdk = Build.VERSION.SDK_INT;
2896 }
2897 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
2898 mode = MODE_IN_CALL;
Eric Laurent1c3408f2021-11-09 12:09:54 +01002899 } else if (mode == MODE_CALL_REDIRECT
2900 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
2901 mode = MODE_IN_CALL;
2902 } else if (mode == MODE_COMMUNICATION_REDIRECT
2903 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
2904 mode = MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002905 }
2906 return mode;
2907 } catch (RemoteException e) {
2908 throw e.rethrowFromSystemServer();
2909 }
2910 }
2911
2912 /**
Nate Myren08635fe2021-04-20 12:04:39 -07002913 * Interface definition of a callback that is notified when the audio mode changes
2914 */
2915 public interface OnModeChangedListener {
2916 /**
2917 * Called on the listener to indicate that the audio mode has changed
2918 *
2919 * @param mode The current audio mode
2920 */
2921 void onModeChanged(@AudioMode int mode);
2922 }
2923
2924 private final Object mModeListenerLock = new Object();
2925 /**
2926 * List of listeners for audio mode and their associated Executor.
2927 * List is lazy-initialized on first registration
2928 */
2929 @GuardedBy("mModeListenerLock")
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002930 private @Nullable ArrayList<ListenerInfo<OnModeChangedListener>> mModeListeners;
Nate Myren08635fe2021-04-20 12:04:39 -07002931
2932 @GuardedBy("mModeListenerLock")
2933 private ModeDispatcherStub mModeDispatcherStub;
2934
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002935 private final class ModeDispatcherStub extends IAudioModeDispatcher.Stub {
2936
2937 public void register(boolean register) {
2938 try {
2939 if (register) {
2940 getService().registerModeDispatcher(this);
2941 } else {
2942 getService().unregisterModeDispatcher(this);
2943 }
2944 } catch (RemoteException e) {
2945 e.rethrowFromSystemServer();
2946 }
2947 }
Nate Myren08635fe2021-04-20 12:04:39 -07002948
2949 @Override
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002950 @SuppressLint("GuardedBy") // lock applied inside callListeners method
Nate Myren08635fe2021-04-20 12:04:39 -07002951 public void dispatchAudioModeChanged(int mode) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002952 CallbackUtil.callListeners(mModeListeners, mModeListenerLock,
2953 (listener) -> listener.onModeChanged(mode));
Nate Myren08635fe2021-04-20 12:04:39 -07002954 }
2955 }
2956
Nate Myren08635fe2021-04-20 12:04:39 -07002957 /**
2958 * Adds a listener to be notified of changes to the audio mode.
2959 * See {@link #getMode()}
2960 * @param executor
2961 * @param listener
2962 */
2963 public void addOnModeChangedListener(
2964 @NonNull @CallbackExecutor Executor executor,
2965 @NonNull OnModeChangedListener listener) {
Nate Myren08635fe2021-04-20 12:04:39 -07002966 synchronized (mModeListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002967 final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
2968 CallbackUtil.addListener("addOnModeChangedListener",
2969 executor, listener, mModeListeners, mModeDispatcherStub,
2970 () -> new ModeDispatcherStub(),
2971 stub -> stub.register(true));
2972 mModeListeners = res.first;
2973 mModeDispatcherStub = res.second;
Nate Myren08635fe2021-04-20 12:04:39 -07002974 }
2975 }
2976
2977 /**
2978 * Removes a previously added listener for changes to audio mode.
2979 * See {@link #getMode()}
2980 * @param listener
2981 */
2982 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
Nate Myren08635fe2021-04-20 12:04:39 -07002983 synchronized (mModeListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08002984 final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
2985 CallbackUtil.removeListener("removeOnModeChangedListener",
2986 listener, mModeListeners, mModeDispatcherStub,
2987 stub -> stub.register(false));
2988 mModeListeners = res.first;
2989 mModeDispatcherStub = res.second;
Nate Myren08635fe2021-04-20 12:04:39 -07002990 }
2991 }
2992
2993 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002994 * Indicates if the platform supports a special call screening and call monitoring mode.
2995 * <p>
2996 * When this mode is supported, it is possible to perform call screening and monitoring
2997 * functions while other use cases like music or movie playback are active.
2998 * <p>
2999 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3000 * call screening mode.
3001 * <p>
3002 * If call screening mode is not supported, setting mode to
3003 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3004 * {@link #getMode()}.
3005 * @return true if call screening mode is supported, false otherwise.
3006 */
3007 public boolean isCallScreeningModeSupported() {
3008 final IAudioService service = getService();
3009 try {
3010 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003012 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013 }
3014 }
3015
3016 /* modes for setMode/getMode/setRoute/getRoute */
3017 /**
3018 * Audio harware modes.
3019 */
3020 /**
3021 * Invalid audio mode.
3022 */
3023 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3024 /**
3025 * Current audio mode. Used to apply audio routing to current mode.
3026 */
3027 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3028 /**
3029 * Normal audio mode: not ringing and no call established.
3030 */
3031 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3032 /**
3033 * Ringing audio mode. An incoming is being signaled.
3034 */
3035 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3036 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003037 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003038 */
3039 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003040 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003041 * In communication audio mode. An audio/video chat or VoIP call is established.
3042 */
3043 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003044 /**
3045 * Call screening in progress. Call is connected and audio is accessible to call
3046 * screening applications but other audio use cases are still possible.
3047 */
3048 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3049
Eric Laurent1c3408f2021-11-09 12:09:54 +01003050 /**
3051 * A telephony call is established and its audio is being redirected to another device.
3052 */
3053 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT;
3054
3055 /**
Eric Laurent961cd3a2021-11-17 15:02:24 +01003056 * An audio/video chat or VoIP call is established and its audio is being redirected to another
Eric Laurent1c3408f2021-11-09 12:09:54 +01003057 * device.
3058 */
3059 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3060
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003061 /** @hide */
3062 @IntDef(flag = false, prefix = "MODE_", value = {
3063 MODE_NORMAL,
3064 MODE_RINGTONE,
3065 MODE_IN_CALL,
3066 MODE_IN_COMMUNICATION,
Eric Laurent1c3408f2021-11-09 12:09:54 +01003067 MODE_CALL_SCREENING,
3068 MODE_CALL_REDIRECT,
3069 MODE_COMMUNICATION_REDIRECT}
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003070 )
3071 @Retention(RetentionPolicy.SOURCE)
3072 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003073
3074 /* Routing bits for setRouting/getRouting API */
3075 /**
3076 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003077 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3078 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 */
Eric Laurenta553c252009-07-17 12:17:14 -07003080 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003082 * Routing audio output to speaker
3083 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3084 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085 */
Eric Laurenta553c252009-07-17 12:17:14 -07003086 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003087 /**
3088 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003089 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3090 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 */
3092 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3093 /**
3094 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003095 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3096 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 */
Eric Laurenta553c252009-07-17 12:17:14 -07003098 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 /**
3100 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003101 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3102 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 */
Eric Laurenta553c252009-07-17 12:17:14 -07003104 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 /**
3106 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003107 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3108 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003109 */
Eric Laurenta553c252009-07-17 12:17:14 -07003110 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003111 /**
3112 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003113 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3114 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115 */
Eric Laurenta553c252009-07-17 12:17:14 -07003116 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117
3118 /**
3119 * Sets the audio routing for a specified mode
3120 *
3121 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3122 * @param routes bit vector of routes requested, created from one or
3123 * more of ROUTE_xxx types. Set bits indicate that route should be on
3124 * @param mask bit vector of routes to change, created from one or more of
3125 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003126 *
3127 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003128 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 */
Eric Laurenta553c252009-07-17 12:17:14 -07003130 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003131 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003132 }
3133
3134 /**
3135 * Returns the current audio routing bit vector for a specified mode.
3136 *
3137 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3138 * @return an audio route bit vector that can be compared with ROUTE_xxx
3139 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003140 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3141 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003143 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003145 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 }
3147
3148 /**
3149 * Checks whether any music is active.
3150 *
3151 * @return true if any music tracks are active.
3152 */
3153 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003154 final IAudioService service = getService();
3155 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003156 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003157 } catch (RemoteException e) {
3158 throw e.rethrowFromSystemServer();
3159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 }
3161
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003162 /**
3163 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003164 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3165 * display). Note that BT audio sinks are not considered remote devices.
3166 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3167 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003168 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003169 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003170 final IAudioService service = getService();
3171 try {
3172 return service.isMusicActive(true /*remotely*/);
3173 } catch (RemoteException e) {
3174 throw e.rethrowFromSystemServer();
3175 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003176 }
3177
3178 /**
3179 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003180 * Checks whether the current audio focus is exclusive.
3181 * @return true if the top of the audio focus stack requested focus
3182 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3183 */
3184 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003185 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003186 try {
3187 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3188 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003189 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003190 }
3191 }
3192
3193 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003194 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003195 * An audio session identifier is a system wide unique identifier for a set of audio streams
3196 * (one or more mixed together).
3197 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3198 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3199 * session ID will be applied to the mixed audio content of the players that share the same
3200 * audio session.
3201 * <p>This method can for instance be used when creating one of the
3202 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3203 * or to specify a session for a speech synthesis utterance
3204 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003205 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003206 * system failed to generate a new session, a condition in which audio playback or recording
3207 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003208 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003209 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003210 int session = AudioSystem.newAudioSessionId();
3211 if (session > 0) {
3212 return session;
3213 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003214 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003215 return ERROR;
3216 }
3217 }
3218
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003219 /**
3220 * A special audio session ID to indicate that the audio session ID isn't known and the
3221 * framework should generate a new value. This can be used when building a new
3222 * {@link AudioTrack} instance with
3223 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3224 */
3225 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3226
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 /*
3229 * Sets a generic audio configuration parameter. The use of these parameters
3230 * are platform dependant, see libaudio
3231 *
3232 * ** Temporary interface - DO NOT USE
3233 *
3234 * TODO: Replace with a more generic key:value get/set mechanism
3235 *
3236 * param key name of parameter to set. Must not be null.
3237 * param value value of parameter. Must not be null.
3238 */
3239 /**
3240 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003241 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003242 */
Eric Laurenta553c252009-07-17 12:17:14 -07003243 @Deprecated public void setParameter(String key, String value) {
3244 setParameters(key+"="+value);
3245 }
3246
3247 /**
3248 * Sets a variable number of parameter values to audio hardware.
3249 *
3250 * @param keyValuePairs list of parameters key value pairs in the form:
3251 * key1=value1;key2=value2;...
3252 *
3253 */
3254 public void setParameters(String keyValuePairs) {
3255 AudioSystem.setParameters(keyValuePairs);
3256 }
3257
3258 /**
William Escandeef429b62021-10-15 18:37:40 +02003259 * @hide
3260 */
3261 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3262 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3263 public void setHfpEnabled(boolean enable) {
3264 AudioSystem.setParameters("hfp_enable=" + enable);
3265 }
3266
3267 /**
3268 * @hide
3269 */
3270 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3271 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3272 public void setHfpVolume(int volume) {
3273 AudioSystem.setParameters("hfp_volume=" + volume);
3274 }
3275
3276 /**
3277 * @hide
3278 */
3279 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3280 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3281 public void setHfpSamplingRate(int rate) {
3282 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3283 }
3284
3285 /**
3286 * @hide
3287 */
3288 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3289 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3290 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3291 boolean hasWbsEnabled) {
3292 AudioSystem.setParameters("bt_headset_name=" + name
3293 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3294 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3295 }
3296
3297 /**
3298 * @hide
3299 */
3300 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3301 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
3302 public void setA2dpSuspended(boolean enable) {
3303 AudioSystem.setParameters("A2dpSuspended=" + enable);
3304 }
3305
3306 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003307 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003308 *
3309 * @param keys list of parameters
3310 * @return list of parameters key value pairs in the form:
3311 * key1=value1;key2=value2;...
3312 */
3313 public String getParameters(String keys) {
3314 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 }
3316
3317 /* Sound effect identifiers */
3318 /**
3319 * Keyboard and direction pad click sound
3320 * @see #playSoundEffect(int)
3321 */
3322 public static final int FX_KEY_CLICK = 0;
3323 /**
3324 * Focus has moved up
3325 * @see #playSoundEffect(int)
3326 */
3327 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3328 /**
3329 * Focus has moved down
3330 * @see #playSoundEffect(int)
3331 */
3332 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3333 /**
3334 * Focus has moved left
3335 * @see #playSoundEffect(int)
3336 */
3337 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3338 /**
3339 * Focus has moved right
3340 * @see #playSoundEffect(int)
3341 */
3342 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3343 /**
3344 * IME standard keypress sound
3345 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 */
3347 public static final int FX_KEYPRESS_STANDARD = 5;
3348 /**
3349 * IME spacebar keypress sound
3350 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 */
3352 public static final int FX_KEYPRESS_SPACEBAR = 6;
3353 /**
3354 * IME delete keypress sound
3355 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003356 */
3357 public static final int FX_KEYPRESS_DELETE = 7;
3358 /**
3359 * IME return_keypress sound
3360 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 */
3362 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003363
3364 /**
3365 * Invalid keypress sound
3366 * @see #playSoundEffect(int)
3367 */
3368 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003369
3370 /**
3371 * Back sound
3372 * @see #playSoundEffect(int)
3373 */
3374 public static final int FX_BACK = 10;
3375
3376 /**
3377 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003378 * <p>
3379 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3380 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003381 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3382 * @see #playSoundEffect(int)
3383 */
3384 public static final int FX_HOME = 11;
3385
3386 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003387 * @hide Navigation repeat sound 1
3388 * <p>
3389 * To be played by the framework when a focus navigation is repeatedly triggered
3390 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003391 * This is currently only used on TV devices.
3392 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3393 * @see #playSoundEffect(int)
3394 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003395 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003396
3397 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003398 * @hide Navigation repeat sound 2
3399 * <p>
3400 * To be played by the framework when a focus navigation is repeatedly triggered
3401 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003402 * This is currently only used on TV devices.
3403 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3404 * @see #playSoundEffect(int)
3405 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003406 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003407
3408 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003409 * @hide Navigation repeat sound 3
3410 * <p>
3411 * To be played by the framework when a focus navigation is repeatedly triggered
3412 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003413 * This is currently only used on TV devices.
3414 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3415 * @see #playSoundEffect(int)
3416 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003417 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003418
3419 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003420 * @hide Navigation repeat sound 4
3421 * <p>
3422 * To be played by the framework when a focus navigation is repeatedly triggered
3423 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003424 * This is currently only used on TV devices.
3425 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3426 * @see #playSoundEffect(int)
3427 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003428 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 /**
3431 * @hide Number of sound effects
3432 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003433 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003434 public static final int NUM_SOUND_EFFECTS = 16;
3435
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003436 /** @hide */
3437 @IntDef(prefix = { "FX_" }, value = {
3438 FX_KEY_CLICK,
3439 FX_FOCUS_NAVIGATION_UP,
3440 FX_FOCUS_NAVIGATION_DOWN,
3441 FX_FOCUS_NAVIGATION_LEFT,
3442 FX_FOCUS_NAVIGATION_RIGHT,
3443 FX_KEYPRESS_STANDARD,
3444 FX_KEYPRESS_SPACEBAR,
3445 FX_KEYPRESS_DELETE,
3446 FX_KEYPRESS_RETURN,
3447 FX_KEYPRESS_INVALID,
3448 FX_BACK
3449 })
3450 @Retention(RetentionPolicy.SOURCE)
3451 public @interface SystemSoundEffect {}
3452
Philip Junker7f1fdff2020-12-03 16:10:41 +01003453 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003454 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003455 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003456 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003457
3458 /**
3459 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003460 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3461 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003462 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003463 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003464 switch (n) {
3465 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003466 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003467 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003468 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003469 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003470 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003471 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003472 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003473 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003474 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003475 return -1;
3476 }
3477 }
3478
3479 /**
3480 * @hide
3481 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003482 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003483 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003484 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003485 } catch (RemoteException e) {
3486
3487 }
3488 }
3489
3490 /**
3491 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003492 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003493 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003494 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003495 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003496 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003497 } catch (RemoteException e) {
3498 throw e.rethrowFromSystemServer();
3499 }
3500 }
3501
3502 /**
3503 * @hide
3504 * @param enabled
3505 */
3506 public void setHomeSoundEffectEnabled(boolean enabled) {
3507 try {
3508 getService().setHomeSoundEffectEnabled(enabled);
3509 } catch (RemoteException e) {
3510
3511 }
3512 }
3513
3514 /**
3515 * @hide
3516 * @return true if the home sound effect is enabled
3517 */
3518 public boolean isHomeSoundEffectEnabled() {
3519 try {
3520 return getService().isHomeSoundEffectEnabled();
3521 } catch (RemoteException e) {
3522 throw e.rethrowFromSystemServer();
3523 }
3524 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525
3526 /**
3527 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003528 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 * NOTE: This version uses the UI settings to determine
3530 * whether sounds are heard or not.
3531 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003532 public void playSoundEffect(@SystemSoundEffect int effectType) {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003533 playSoundEffect(effectType, UserHandle.USER_CURRENT);
Jason Monk0c37ba32014-09-08 15:34:23 -04003534 }
3535
3536 /**
3537 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003538 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003539 * @param userId The current user to pull sound settings from
3540 * NOTE: This version uses the UI settings to determine
3541 * whether sounds are heard or not.
3542 * @hide
3543 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003544 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003545 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3546 return;
3547 }
3548
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003549 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003550 try {
Oscar Azucena21f2c4d2021-10-26 18:06:54 -07003551 service.playSoundEffect(effectType, userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003552 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003553 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 }
3555 }
3556
3557 /**
3558 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003559 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003560 * @param volume Sound effect volume.
3561 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3562 * 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 -08003563 * NOTE: This version is for applications that have their own
3564 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003566 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3568 return;
3569 }
3570
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003571 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 try {
3573 service.playSoundEffectVolume(effectType, volume);
3574 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003575 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 }
3577 }
3578
3579 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 * Load Sound effects.
3581 * This method must be called when sound effects are enabled.
3582 */
3583 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003584 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 try {
3586 service.loadSoundEffects();
3587 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003588 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 }
3590 }
3591
3592 /**
3593 * Unload Sound effects.
3594 * This method can be called to free some memory when
3595 * sound effects are disabled.
3596 */
3597 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003598 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003599 try {
3600 service.unloadSoundEffects();
3601 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003602 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003603 }
3604 }
3605
Eric Laurent4050c932009-07-08 02:52:14 -07003606 /**
Andy Hung69836952020-03-26 01:00:15 -07003607 * @hide
3608 */
3609 public static String audioFocusToString(int focus) {
3610 switch (focus) {
3611 case AUDIOFOCUS_NONE:
3612 return "AUDIOFOCUS_NONE";
3613 case AUDIOFOCUS_GAIN:
3614 return "AUDIOFOCUS_GAIN";
3615 case AUDIOFOCUS_GAIN_TRANSIENT:
3616 return "AUDIOFOCUS_GAIN_TRANSIENT";
3617 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3618 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3619 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3620 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3621 case AUDIOFOCUS_LOSS:
3622 return "AUDIOFOCUS_LOSS";
3623 case AUDIOFOCUS_LOSS_TRANSIENT:
3624 return "AUDIOFOCUS_LOSS_TRANSIENT";
3625 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3626 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3627 default:
3628 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3629 }
3630 }
3631
3632 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003633 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003634 */
3635 public static final int AUDIOFOCUS_NONE = 0;
3636
3637 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003638 * 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 -07003639 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003640 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003641 */
3642 public static final int AUDIOFOCUS_GAIN = 1;
3643 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003644 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3645 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3646 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003647 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003648 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003649 */
3650 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003651 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003652 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003653 * amount of time, and where it is acceptable for other audio applications to keep playing
3654 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003655 * Examples of temporary changes are the playback of driving directions where playback of music
3656 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003657 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003658 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3659 */
3660 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3661 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003662 * Used to indicate a temporary request of audio focus, anticipated to last a short
3663 * amount of time, during which no other applications, or system components, should play
3664 * anything. Examples of exclusive and transient audio focus requests are voice
3665 * memo recording and speech recognition, during which the system shouldn't play any
3666 * notifications, and media playback should have paused.
3667 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3668 */
3669 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3670 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003671 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003672 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003673 */
3674 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3675 /**
3676 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003677 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003678 */
3679 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3680 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003681 * 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 -07003682 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3683 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003684 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003685 */
3686 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3687 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003688
3689 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003690 * Interface definition for a callback to be invoked when the audio focus of the system is
3691 * updated.
3692 */
3693 public interface OnAudioFocusChangeListener {
3694 /**
3695 * Called on the listener to notify it the audio focus for this listener has been changed.
3696 * The focusChange value indicates whether the focus was gained,
3697 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3698 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003699 * When losing focus, listeners can use the focus change information to decide what
3700 * behavior to adopt when losing focus. A music player could for instance elect to lower
3701 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3702 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003703 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003704 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003705 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003706 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003707 }
3708
3709 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003710 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3711 */
3712 private static class FocusRequestInfo {
3713 @NonNull final AudioFocusRequest mRequest;
3714 @Nullable final Handler mHandler;
3715 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3716 mRequest = afr;
3717 mHandler = handler;
3718 }
3719 }
3720
3721 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003722 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3723 * to actual listener objects.
3724 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003725 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003726 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3727 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003728
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003729 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003730 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003731 }
3732
3733 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003734 * Handler for events (audio focus change, recording config change) coming from the
3735 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003736 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003737 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003738 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003739
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003740 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003741 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003742 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003743 private final static int MSSG_FOCUS_CHANGE = 0;
3744 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003745 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003746
3747 /**
3748 * Helper class to handle the forwarding of audio service events to the appropriate listener
3749 */
3750 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003751 private final Handler mHandler;
3752
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003753 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003754 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003755 if (handler == null) {
3756 if ((looper = Looper.myLooper()) == null) {
3757 looper = Looper.getMainLooper();
3758 }
3759 } else {
3760 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003761 }
3762
3763 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003764 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003765 mHandler = new Handler(looper) {
3766 @Override
3767 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003768 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003769 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003770 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3771 if (fri != null) {
3772 final OnAudioFocusChangeListener listener =
3773 fri.mRequest.getOnAudioFocusChangeListener();
3774 if (listener != null) {
3775 Log.d(TAG, "dispatching onAudioFocusChange("
3776 + msg.arg1 + ") to " + msg.obj);
3777 listener.onAudioFocusChange(msg.arg1);
3778 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003779 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003780 } break;
3781 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08003782 final RecordConfigChangeCallbackData cbData =
3783 (RecordConfigChangeCallbackData) msg.obj;
3784 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07003785 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08003786 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003787 } break;
3788 case MSSG_PLAYBACK_CONFIG_CHANGE: {
3789 final PlaybackConfigChangeCallbackData cbData =
3790 (PlaybackConfigChangeCallbackData) msg.obj;
3791 if (cbData.mCb != null) {
3792 if (DEBUG) {
3793 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3794 }
3795 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3796 }
3797 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003798 default:
3799 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003800 }
3801 }
3802 };
3803 } else {
3804 mHandler = null;
3805 }
3806 }
3807
3808 Handler getHandler() {
3809 return mHandler;
3810 }
3811 }
3812
Glenn Kasten30c918c2011-11-10 17:56:41 -08003813 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003814 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003815 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003816 final FocusRequestInfo fri = findFocusRequestInfo(id);
3817 if (fri != null) {
3818 final OnAudioFocusChangeListener listener =
3819 fri.mRequest.getOnAudioFocusChangeListener();
3820 if (listener != null) {
3821 final Handler h = (fri.mHandler == null) ?
3822 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3823 final Message m = h.obtainMessage(
3824 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3825 id/*obj*/);
3826 h.sendMessage(m);
3827 }
3828 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003829 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003830
3831 @Override
3832 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3833 synchronized (mFocusRequestsLock) {
3834 // TODO use generation counter as the key instead
3835 final BlockingFocusResultReceiver focusReceiver =
3836 mFocusRequestsAwaitingResult.remove(clientId);
3837 if (focusReceiver != null) {
3838 focusReceiver.notifyResult(requestResult);
3839 } else {
3840 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3841 }
3842 }
3843 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003844 };
3845
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003846 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003847 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07003848 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003849 } else {
3850 return new String(this.toString() + l.toString());
3851 }
3852 }
3853
3854 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003855 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003856 * Registers a listener to be called when audio focus changes and keeps track of the associated
3857 * focus request (including Handler to use for the listener).
3858 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003859 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003860 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3861 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3862 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3863 new ServiceEventHandlerDelegate(h).getHandler());
3864 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3865 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003866 }
3867
3868 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003869 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003870 * Causes the specified listener to not be called anymore when focus is gained or lost.
3871 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003872 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003873 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003874 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003875 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003876 }
3877
3878
3879 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003880 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003881 */
3882 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3883 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003884 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003885 */
3886 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003887 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003888 * A focus change request whose granting is delayed: the request was successful, but the
3889 * requester will only be granted audio focus once the condition that prevented immediate
3890 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003891 * See {@link #requestAudioFocus(AudioFocusRequest)} and
3892 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003893 */
3894 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003895
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003896 /** @hide */
3897 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3898 AUDIOFOCUS_REQUEST_FAILED,
3899 AUDIOFOCUS_REQUEST_GRANTED,
3900 AUDIOFOCUS_REQUEST_DELAYED }
3901 )
3902 @Retention(RetentionPolicy.SOURCE)
3903 public @interface FocusRequestResult {}
3904
3905 /**
3906 * @hide
3907 * code returned when a synchronous focus request on the client-side is to be blocked
3908 * until the external audio focus policy decides on the response for the client
3909 */
3910 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
3911
3912 /**
3913 * Timeout duration in ms when waiting on an external focus policy for the result for a
3914 * focus request
3915 */
3916 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
3917
3918 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
3919
3920 private final Object mFocusRequestsLock = new Object();
3921 /**
3922 * Map of all receivers of focus request results, one per unresolved focus request.
3923 * Receivers are added before sending the request to the external focus policy,
3924 * and are removed either after receiving the result, or after the timeout.
3925 * This variable is lazily initialized.
3926 */
3927 @GuardedBy("mFocusRequestsLock")
3928 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
3929
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003930
3931 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003932 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003933 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003934 * @param l the listener to be notified of audio focus changes
3935 * @param streamType the main audio stream type affected by the focus request
3936 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
3937 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003938 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003939 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
3940 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07003941 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
3942 * that benefits from the system not playing disruptive sounds like notifications, for
3943 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003944 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003945 * as the playback of a song or a video.
3946 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08003947 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003948 */
3949 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08003950 PlayerBase.deprecateStreamTypeForPlayback(streamType,
3951 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003952 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003953
3954 try {
3955 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
3956 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
3957 // AUDIOFOCUS_FLAG_DELAY_OK flag
3958 status = requestAudioFocus(l,
3959 new AudioAttributes.Builder()
3960 .setInternalLegacyStreamType(streamType).build(),
3961 durationHint,
3962 0 /* flags, legacy behavior */);
3963 } catch (IllegalArgumentException e) {
3964 Log.e(TAG, "Audio focus request denied due to ", e);
3965 }
3966
3967 return status;
3968 }
3969
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003970 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003971 /**
3972 * @hide
3973 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
3974 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
3975 * the system is in a state where focus cannot change, but be granted focus later when
3976 * this condition ends.
3977 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003978 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003979 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003980 /**
3981 * @hide
3982 * Use this flag when requesting audio focus to indicate that the requester
3983 * will pause its media playback (if applicable) when losing audio focus with
3984 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
3985 * <br>On some platforms, the ducking may be handled without the application being aware of it
3986 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
3987 * content, such as audio book or podcast players, ducking may never be acceptable, and will
3988 * thus always pause. This flag enables them to be declared as such whenever they request focus.
3989 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003990 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003991 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
3992 /**
3993 * @hide
3994 * Use this flag to lock audio focus so granting is temporarily disabled.
3995 * <br>This flag can only be used by owners of a registered
3996 * {@link android.media.audiopolicy.AudioPolicy} in
3997 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
3998 */
3999 @SystemApi
4000 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004001
4002 /**
4003 * @hide
4004 * flag set on test API calls,
4005 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
4006 * note that it isn't used in conjunction with other flags, it is passed as the single
4007 * value for flags */
4008 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004009 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004010 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4011 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004012 /** @hide */
4013 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004014 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004015
4016 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004017 * Request audio focus.
4018 * See the {@link AudioFocusRequest} for information about the options available to configure
4019 * your request, and notification of focus gain and loss.
4020 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4021 * requested.
4022 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4023 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4024 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4025 * is requested without building the {@link AudioFocusRequest} with
4026 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4027 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004028 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004029 */
4030 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004031 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004032 }
4033
4034 /**
4035 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4036 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4037 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4038 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4039 * @throws IllegalArgumentException if passed a null argument
4040 */
4041 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4042 if (focusRequest == null) {
4043 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4044 }
4045 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4046 focusRequest.getAudioAttributes());
4047 }
4048
4049 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004050 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004051 * Request audio focus.
4052 * Send a request to obtain the audio focus. This method differs from
4053 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4054 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004055 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4056 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4057 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4058 * requesting audio focus.
4059 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4060 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4061 * for the playback of driving directions, or notifications sounds.
4062 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4063 * the previous focus owner to keep playing if it ducks its audio output.
4064 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4065 * that benefits from the system not playing disruptive sounds like notifications, for
4066 * usecases such as voice memo recording, or speech recognition.
4067 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4068 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004069 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4070 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004071 * <br>Use 0 when not using any flags for the request, which behaves like
4072 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4073 * focus is granted immediately, or the grant request fails because the system is in a
4074 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004075 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4076 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4077 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4078 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4079 * @throws IllegalArgumentException
4080 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004081 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004082 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004083 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004084 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004085 int durationHint,
4086 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004087 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4088 throw new IllegalArgumentException("Invalid flags 0x"
4089 + Integer.toHexString(flags).toUpperCase());
4090 }
4091 return requestAudioFocus(l, requestAttributes, durationHint,
4092 flags & AUDIOFOCUS_FLAGS_APPS,
4093 null /* no AudioPolicy*/);
4094 }
4095
4096 /**
4097 * @hide
4098 * Request or lock audio focus.
4099 * This method is to be used by system components that have registered an
4100 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4101 * so focus granting is temporarily disabled.
4102 * @param l see the description of the same parameter in
4103 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4104 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4105 * requesting audio focus.
4106 * @param durationHint see the description of the same parameter in
4107 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4108 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004109 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004110 * <br>Use 0 when not using any flags for the request, which behaves like
4111 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4112 * focus is granted immediately, or the grant request fails because the system is in a
4113 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004114 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4115 * focus, or null.
4116 * @return see the description of the same return value in
4117 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4118 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004119 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004120 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004121 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004122 @RequiresPermission(anyOf= {
4123 android.Manifest.permission.MODIFY_PHONE_STATE,
4124 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4125 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004126 public int requestAudioFocus(OnAudioFocusChangeListener l,
4127 @NonNull AudioAttributes requestAttributes,
4128 int durationHint,
4129 int flags,
4130 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004131 // parameter checking
4132 if (requestAttributes == null) {
4133 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4134 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004135 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004136 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004137 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004138 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004139 throw new IllegalArgumentException("Illegal flags 0x"
4140 + Integer.toHexString(flags).toUpperCase());
4141 }
4142 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4143 throw new IllegalArgumentException(
4144 "Illegal null focus listener when flagged as accepting delayed focus grant");
4145 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004146 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4147 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4148 throw new IllegalArgumentException(
4149 "Illegal null focus listener when flagged as pausing instead of ducking");
4150 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004151 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4152 throw new IllegalArgumentException(
4153 "Illegal null audio policy when locking audio focus");
4154 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004155
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004156 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004157 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004158 .setAudioAttributes(requestAttributes)
4159 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4160 == AUDIOFOCUS_FLAG_DELAY_OK)
4161 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4162 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4163 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4164 .build();
4165 return requestAudioFocus(afr, ap);
4166 }
4167
4168 /**
4169 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004170 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4171 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4172 * @param afr the parameters of the request
4173 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4174 * @param clientFakeUid the UID of the client, here an arbitrary int,
4175 * doesn't have to be a real UID
4176 * @param clientTargetSdk the target SDK used by the client
4177 * @return return code indicating status of the request
4178 */
4179 @TestApi
4180 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4181 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4182 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4183 Objects.requireNonNull(afr);
4184 Objects.requireNonNull(clientFakeId);
4185 try {
4186 return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4187 afr.getFocusGain(),
4188 mICallBack,
4189 mAudioFocusDispatcher,
4190 clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
4191 } catch (RemoteException e) {
4192 throw e.rethrowFromSystemServer();
4193 }
4194 }
4195
4196 /**
4197 * @hide
4198 * Test API to abandon audio focus for an arbitrary client.
4199 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4200 * @param afr the parameters used for the request
4201 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4202 * would be requesting
4203 * @return return code indicating status of the request
4204 */
4205 @TestApi
4206 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4207 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4208 @NonNull String clientFakeId) {
4209 Objects.requireNonNull(afr);
4210 Objects.requireNonNull(clientFakeId);
4211 try {
4212 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4213 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4214 } catch (RemoteException e) {
4215 throw e.rethrowFromSystemServer();
4216 }
4217 }
4218
4219 /**
4220 * @hide
4221 * Return the duration of the fade out applied when a player of the given AudioAttributes
4222 * is losing audio focus
4223 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4224 * @return a duration in ms, 0 indicates no fade out is applied
4225 */
4226 @TestApi
4227 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4228 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4229 {
4230 Objects.requireNonNull(aa);
4231 try {
4232 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4233 } catch (RemoteException e) {
4234 throw e.rethrowFromSystemServer();
4235 }
4236 }
4237
4238 /**
4239 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004240 * Request or lock audio focus.
4241 * This method is to be used by system components that have registered an
4242 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4243 * so focus granting is temporarily disabled.
4244 * @param afr see the description of the same parameter in
4245 * {@link #requestAudioFocus(AudioFocusRequest)}
4246 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4247 * focus, or null.
4248 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4249 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4250 * @throws NullPointerException if the AudioFocusRequest is null
4251 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4252 */
4253 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004254 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004255 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4256 if (afr == null) {
4257 throw new NullPointerException("Illegal null AudioFocusRequest");
4258 }
4259 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4260 if (afr.locksFocus() && ap == null) {
4261 throw new IllegalArgumentException(
4262 "Illegal null audio policy when locking audio focus");
4263 }
4264 registerAudioFocusRequest(afr);
4265 final IAudioService service = getService();
4266 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004267 int sdk;
4268 try {
4269 sdk = getContext().getApplicationInfo().targetSdkVersion;
4270 } catch (NullPointerException e) {
4271 // some tests don't have a Context
4272 sdk = Build.VERSION.SDK_INT;
4273 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004274
4275 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4276 final BlockingFocusResultReceiver focusReceiver;
4277 synchronized (mFocusRequestsLock) {
4278 try {
4279 // TODO status contains result and generation counter for ext policy
4280 status = service.requestAudioFocus(afr.getAudioAttributes(),
4281 afr.getFocusGain(), mICallBack,
4282 mAudioFocusDispatcher,
4283 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004284 getContext().getOpPackageName() /* package name */,
4285 getContext().getAttributionTag(),
4286 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004287 ap != null ? ap.cb() : null,
4288 sdk);
4289 } catch (RemoteException e) {
4290 throw e.rethrowFromSystemServer();
4291 }
4292 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4293 // default path with no external focus policy
4294 return status;
4295 }
4296 if (mFocusRequestsAwaitingResult == null) {
4297 mFocusRequestsAwaitingResult =
4298 new HashMap<String, BlockingFocusResultReceiver>(1);
4299 }
4300 focusReceiver = new BlockingFocusResultReceiver(clientId);
4301 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004302 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004303 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4304 if (DEBUG && !focusReceiver.receivedResult()) {
4305 Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4306 }
4307 synchronized (mFocusRequestsLock) {
4308 mFocusRequestsAwaitingResult.remove(clientId);
4309 }
4310 return focusReceiver.requestResult();
4311 }
4312
4313 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4314 private static final class SafeWaitObject {
4315 private boolean mQuit = false;
4316
4317 public void safeNotify() {
4318 synchronized (this) {
4319 mQuit = true;
4320 this.notify();
4321 }
4322 }
4323
4324 public void safeWait(long millis) throws InterruptedException {
4325 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4326 synchronized (this) {
4327 while (!mQuit) {
4328 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4329 if (timeToWait < 0) { break; }
4330 this.wait(timeToWait);
4331 }
4332 }
4333 }
4334 }
4335
4336 private static final class BlockingFocusResultReceiver {
4337 private final SafeWaitObject mLock = new SafeWaitObject();
4338 @GuardedBy("mLock")
4339 private boolean mResultReceived = false;
4340 // request denied by default (e.g. timeout)
4341 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4342 private final String mFocusClientId;
4343
4344 BlockingFocusResultReceiver(String clientId) {
4345 mFocusClientId = clientId;
4346 }
4347
4348 boolean receivedResult() { return mResultReceived; }
4349 int requestResult() { return mFocusRequestResult; }
4350
4351 void notifyResult(int requestResult) {
4352 synchronized (mLock) {
4353 mResultReceived = true;
4354 mFocusRequestResult = requestResult;
4355 mLock.safeNotify();
4356 }
4357 }
4358
4359 public void waitForResult(long timeOutMs) {
4360 synchronized (mLock) {
4361 if (mResultReceived) {
4362 // the result was received before waiting
4363 return;
4364 }
4365 try {
4366 mLock.safeWait(timeOutMs);
4367 } catch (InterruptedException e) { }
4368 }
4369 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004370 }
4371
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004372 /**
4373 * @hide
4374 * Used internally by telephony package to request audio focus. Will cause the focus request
4375 * to be associated with the "voice communication" identifier only used in AudioService
4376 * to identify this use case.
4377 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4378 * the establishment of the call
4379 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4380 * media applications resume after a call
4381 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004382 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004383 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004384 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004385 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004386 service.requestAudioFocus(new AudioAttributes.Builder()
4387 .setInternalLegacyStreamType(streamType).build(),
4388 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004389 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004390 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004391 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004392 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004393 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004394 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004395 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004396 }
4397 }
4398
4399 /**
4400 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004401 * Return the volume ramping time for a sound to be played after the given focus request,
4402 * and to play a sound of the given attributes
4403 * @param focusGain
4404 * @param attr
4405 * @return
4406 */
4407 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004408 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004409 try {
4410 return service.getFocusRampTimeMs(focusGain, attr);
4411 } catch (RemoteException e) {
4412 throw e.rethrowFromSystemServer();
4413 }
4414 }
4415
4416 /**
4417 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004418 * Set the result to the audio focus request received through
4419 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4420 * @param afi the information about the focus requester
4421 * @param requestResult the result to the focus request to be passed to the requester
4422 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4423 */
4424 @SystemApi
4425 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4426 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4427 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4428 if (afi == null) {
4429 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4430 }
4431 if (ap == null) {
4432 throw new IllegalArgumentException("Illegal null AudioPolicy");
4433 }
4434 final IAudioService service = getService();
4435 try {
4436 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4437 } catch (RemoteException e) {
4438 throw e.rethrowFromSystemServer();
4439 }
4440 }
4441
4442 /**
4443 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004444 * Notifies an application with a focus listener of gain or loss of audio focus.
4445 * This method can only be used by owners of an {@link AudioPolicy} configured with
4446 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4447 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4448 * that was received by the {@code AudioPolicy} through
4449 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4450 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4451 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4452 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4453 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4454 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4455 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4456 * <br>For the focus gain, the change type should be the same as the app requested.
4457 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4458 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4459 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4460 * if there was an error sending the request.
4461 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4462 */
4463 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004464 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004465 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4466 @NonNull AudioPolicy ap) {
4467 if (afi == null) {
4468 throw new NullPointerException("Illegal null AudioFocusInfo");
4469 }
4470 if (ap == null) {
4471 throw new NullPointerException("Illegal null AudioPolicy");
4472 }
4473 final IAudioService service = getService();
4474 try {
4475 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4476 } catch (RemoteException e) {
4477 throw e.rethrowFromSystemServer();
4478 }
4479 }
4480
4481 /**
4482 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004483 * Used internally by telephony package to abandon audio focus, typically after a call or
4484 * when ringing ends and the call is rejected or not answered.
4485 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4486 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004487 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004488 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004489 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004490 try {
John Spurlock61560172015-02-06 19:46:04 -05004491 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004492 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004493 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004494 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004495 }
4496 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004497
4498 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004499 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4500 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004501 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004502 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004503 */
4504 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004505 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4506 }
4507
4508 /**
4509 * @hide
4510 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4511 * @param l the listener with which focus was requested.
4512 * @param aa the {@link AudioAttributes} with which audio focus was requested
4513 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004514 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004515 */
4516 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004517 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4518 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004519 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004520 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004521 unregisterAudioFocusRequest(l);
4522 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004523 try {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004524 status = service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004525 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004526 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004527 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004528 }
4529 return status;
4530 }
4531
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004532 //====================================================================
4533 // Remote Control
4534 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004535 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004536 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4537 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004538 * in the application manifest. The package of the component must match that of
4539 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004540 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004541 */
RoboErikb214efb2014-07-24 13:20:30 -07004542 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004543 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004544 if (eventReceiver == null) {
4545 return;
4546 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004547 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004548 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4549 "receiver and context package names don't match");
4550 return;
4551 }
4552 // construct a PendingIntent for the media button and register it
4553 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4554 // the associated intent will be handled by the component being registered
4555 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004556 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004557 0/*requestCode, ignored*/, mediaButtonIntent,
4558 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004559 registerMediaButtonIntent(pi, eventReceiver);
4560 }
4561
4562 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004563 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4564 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4565 * the buttons to go to any PendingIntent. Note that you should only use this form if
4566 * you know you will continue running for the full time until unregistering the
4567 * PendingIntent.
4568 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004569 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4570 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4571 * media button that was pressed.
4572 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004573 */
RoboErikb214efb2014-07-24 13:20:30 -07004574 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004575 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4576 if (eventReceiver == null) {
4577 return;
4578 }
4579 registerMediaButtonIntent(eventReceiver, null);
4580 }
4581
4582 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004583 * @hide
4584 * no-op if (pi == null) or (eventReceiver == null)
4585 */
4586 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004587 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004588 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4589 return;
4590 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004591 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4592 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004593 }
4594
4595 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004596 * Unregister the receiver of MEDIA_BUTTON intents.
4597 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4598 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004599 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004600 */
RoboErikb214efb2014-07-24 13:20:30 -07004601 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004602 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004603 if (eventReceiver == null) {
4604 return;
4605 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004606 // construct a PendingIntent for the media button and unregister it
4607 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4608 // the associated intent will be handled by the component being registered
4609 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004610 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004611 0/*requestCode, ignored*/, mediaButtonIntent,
4612 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004613 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004614 }
4615
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004616 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004617 * Unregister the receiver of MEDIA_BUTTON intents.
4618 * @param eventReceiver same PendingIntent that was registed with
4619 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004620 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004621 */
RoboErikb214efb2014-07-24 13:20:30 -07004622 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004623 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4624 if (eventReceiver == null) {
4625 return;
4626 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004627 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004628 }
4629
4630 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004631 * @hide
4632 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004633 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004634 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004635 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004636 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004637
4638 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004639 * Registers the remote control client for providing information to display on the remote
4640 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004641 * @param rcClient The remote control client from which remote controls will receive
4642 * information to display.
4643 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004644 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004645 */
RoboErikb214efb2014-07-24 13:20:30 -07004646 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004647 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004648 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004649 return;
4650 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004651 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004652 }
4653
4654 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004655 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004656 * remote controls.
4657 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004658 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004659 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004660 */
RoboErikb214efb2014-07-24 13:20:30 -07004661 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004662 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004663 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004664 return;
4665 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004666 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004667 }
4668
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004669 /**
RoboErika66c40b2014-08-15 15:21:41 -07004670 * Registers a {@link RemoteController} instance for it to receive media
4671 * metadata updates and playback state information from applications using
4672 * {@link RemoteControlClient}, and control their playback.
4673 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004674 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004675 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004676 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004677 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004678 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004679 * @return true if the {@link RemoteController} was successfully registered,
4680 * false if an error occurred, due to an internal system error, or
4681 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004682 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004683 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4684 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004685 */
RoboErikb214efb2014-07-24 13:20:30 -07004686 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004687 public boolean registerRemoteController(RemoteController rctlr) {
4688 if (rctlr == null) {
4689 return false;
4690 }
RoboErik430fc482014-06-12 15:49:20 -07004691 rctlr.startListeningToSessions();
4692 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004693 }
4694
4695 /**
RoboErika66c40b2014-08-15 15:21:41 -07004696 * Unregisters a {@link RemoteController}, causing it to no longer receive
4697 * media metadata and playback state information, and no longer be capable
4698 * of controlling playback.
4699 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004700 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004701 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004702 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4703 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004704 */
RoboErikb214efb2014-07-24 13:20:30 -07004705 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004706 public void unregisterRemoteController(RemoteController rctlr) {
4707 if (rctlr == null) {
4708 return;
4709 }
RoboErik430fc482014-06-12 15:49:20 -07004710 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004711 }
4712
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004713
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004714 //====================================================================
4715 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004716 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004717 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004718 * Register the given {@link AudioPolicy}.
4719 * This call is synchronous and blocks until the registration process successfully completed
4720 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004721 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004722 * @return {@link #ERROR} if there was an error communicating with the registration service
4723 * or if the user doesn't have the required
4724 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4725 * {@link #SUCCESS} otherwise.
4726 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004727 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004728 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004729 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004730 return registerAudioPolicyStatic(policy);
4731 }
4732
4733 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004734 if (policy == null) {
4735 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4736 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004737 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004738 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004739 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004740 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07004741 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4742 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004743 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004744 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004745 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004746 } else {
4747 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004748 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004749 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004750 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004751 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004752 }
4753 return SUCCESS;
4754 }
4755
4756 /**
4757 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004758 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004759 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004760 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004761 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004762 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004763 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004764 unregisterAudioPolicyAsyncStatic(policy);
4765 }
4766
4767 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004768 if (policy == null) {
4769 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4770 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004771 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004772 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004773 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004774 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004775 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004776 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004777 }
4778 }
4779
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004780 /**
4781 * @hide
4782 * Unregisters an {@link AudioPolicy} synchronously.
4783 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4784 * associated with mixes of this policy.
4785 * @param policy the non-null {@link AudioPolicy} to unregister.
4786 */
4787 @SystemApi
4788 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4789 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4790 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4791 final IAudioService service = getService();
4792 try {
4793 policy.invalidateCaptorsAndInjectors();
4794 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004795 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004796 } catch (RemoteException e) {
4797 throw e.rethrowFromSystemServer();
4798 }
4799 }
4800
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07004801 /**
4802 * @hide
4803 * @return true if an AudioPolicy was previously registered
4804 */
4805 @TestApi
4806 public boolean hasRegisteredDynamicPolicy() {
4807 final IAudioService service = getService();
4808 try {
4809 return service.hasRegisteredDynamicPolicy();
4810 } catch (RemoteException e) {
4811 throw e.rethrowFromSystemServer();
4812 }
4813 }
4814
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004815 //====================================================================
4816 // Notification of playback activity & playback configuration
4817 /**
4818 * Interface for receiving update notifications about the playback activity on the system.
4819 * Extend this abstract class and register it with
4820 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4821 * to be notified.
4822 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4823 * configuration.
4824 * @see AudioPlaybackConfiguration
4825 */
4826 public static abstract class AudioPlaybackCallback {
4827 /**
4828 * Called whenever the playback activity and configuration has changed.
4829 * @param configs list containing the results of
4830 * {@link AudioManager#getActivePlaybackConfigurations()}.
4831 */
4832 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4833 }
4834
4835 private static class AudioPlaybackCallbackInfo {
4836 final AudioPlaybackCallback mCb;
4837 final Handler mHandler;
4838 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4839 mCb = cb;
4840 mHandler = handler;
4841 }
4842 }
4843
4844 private final static class PlaybackConfigChangeCallbackData {
4845 final AudioPlaybackCallback mCb;
4846 final List<AudioPlaybackConfiguration> mConfigs;
4847
4848 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4849 List<AudioPlaybackConfiguration> configs) {
4850 mCb = cb;
4851 mConfigs = configs;
4852 }
4853 }
4854
4855 /**
4856 * Register a callback to be notified of audio playback changes through
4857 * {@link AudioPlaybackCallback}
4858 * @param cb non-null callback to register
4859 * @param handler the {@link Handler} object for the thread on which to execute
4860 * the callback. If <code>null</code>, the {@link Handler} associated with the main
4861 * {@link Looper} will be used.
4862 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08004863 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4864 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004865 {
4866 if (cb == null) {
4867 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4868 }
4869
4870 synchronized(mPlaybackCallbackLock) {
4871 // lazy initialization of the list of playback callbacks
4872 if (mPlaybackCallbackList == null) {
4873 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4874 }
4875 final int oldCbCount = mPlaybackCallbackList.size();
4876 if (!hasPlaybackCallback_sync(cb)) {
4877 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4878 new ServiceEventHandlerDelegate(handler).getHandler()));
4879 final int newCbCount = mPlaybackCallbackList.size();
4880 if ((oldCbCount == 0) && (newCbCount > 0)) {
4881 // register binder for callbacks
4882 try {
4883 getService().registerPlaybackCallback(mPlayCb);
4884 } catch (RemoteException e) {
4885 throw e.rethrowFromSystemServer();
4886 }
4887 }
4888 } else {
4889 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4890 + "registered callback");
4891 }
4892 }
4893 }
4894
4895 /**
4896 * Unregister an audio playback callback previously registered with
4897 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4898 * @param cb non-null callback to unregister
4899 */
4900 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4901 if (cb == null) {
4902 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4903 }
4904 synchronized(mPlaybackCallbackLock) {
4905 if (mPlaybackCallbackList == null) {
4906 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4907 + " that was never registered");
4908 return;
4909 }
4910 final int oldCbCount = mPlaybackCallbackList.size();
4911 if (removePlaybackCallback_sync(cb)) {
4912 final int newCbCount = mPlaybackCallbackList.size();
4913 if ((oldCbCount > 0) && (newCbCount == 0)) {
4914 // unregister binder for callbacks
4915 try {
4916 getService().unregisterPlaybackCallback(mPlayCb);
4917 } catch (RemoteException e) {
4918 throw e.rethrowFromSystemServer();
4919 }
4920 }
4921 } else {
4922 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4923 + " already unregistered or never registered");
4924 }
4925 }
4926 }
4927
4928 /**
4929 * Returns the current active audio playback configurations of the device
4930 * @return a non-null list of playback configurations. An empty list indicates there is no
4931 * playback active when queried.
4932 * @see AudioPlaybackConfiguration
4933 */
4934 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
4935 final IAudioService service = getService();
4936 try {
4937 return service.getActivePlaybackConfigurations();
4938 } catch (RemoteException e) {
4939 throw e.rethrowFromSystemServer();
4940 }
4941 }
4942
4943 /**
4944 * All operations on this list are sync'd on mPlaybackCallbackLock.
4945 * List is lazy-initialized in
4946 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4947 * List can be null.
4948 */
4949 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
4950 private final Object mPlaybackCallbackLock = new Object();
4951
4952 /**
4953 * Must be called synchronized on mPlaybackCallbackLock
4954 */
4955 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4956 if (mPlaybackCallbackList != null) {
4957 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4958 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4959 return true;
4960 }
4961 }
4962 }
4963 return false;
4964 }
4965
4966 /**
4967 * Must be called synchronized on mPlaybackCallbackLock
4968 */
4969 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4970 if (mPlaybackCallbackList != null) {
4971 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4972 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4973 mPlaybackCallbackList.remove(i);
4974 return true;
4975 }
4976 }
4977 }
4978 return false;
4979 }
4980
4981 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004982 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07004983 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
4984 boolean flush) {
4985 if (flush) {
4986 Binder.flushPendingCommands();
4987 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004988 synchronized(mPlaybackCallbackLock) {
4989 if (mPlaybackCallbackList != null) {
4990 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4991 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
4992 if (arci.mHandler != null) {
4993 final Message m = arci.mHandler.obtainMessage(
4994 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
4995 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
4996 arci.mHandler.sendMessage(m);
4997 }
4998 }
4999 }
5000 }
5001 }
5002
5003 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005004
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005005 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08005006 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005007 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005008 * Interface for receiving update notifications about the recording configuration. Extend
5009 * this abstract class and register it with
5010 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5011 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005012 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5013 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005014 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005015 */
5016 public static abstract class AudioRecordingCallback {
5017 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005018 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005019 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005020 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005021 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005022 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005023 }
5024
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005025 private static class AudioRecordingCallbackInfo {
5026 final AudioRecordingCallback mCb;
5027 final Handler mHandler;
5028 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5029 mCb = cb;
5030 mHandler = handler;
5031 }
5032 }
5033
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005034 private final static class RecordConfigChangeCallbackData {
5035 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005036 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005037
5038 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005039 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005040 mCb = cb;
5041 mConfigs = configs;
5042 }
5043 }
5044
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005045 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005046 * Register a callback to be notified of audio recording changes through
5047 * {@link AudioRecordingCallback}
5048 * @param cb non-null callback to register
5049 * @param handler the {@link Handler} object for the thread on which to execute
5050 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5051 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005052 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005053 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5054 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005055 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005056 if (cb == null) {
5057 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5058 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005059
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005060 synchronized(mRecordCallbackLock) {
5061 // lazy initialization of the list of recording callbacks
5062 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005063 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005064 }
5065 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005066 if (!hasRecordCallback_sync(cb)) {
5067 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5068 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005069 final int newCbCount = mRecordCallbackList.size();
5070 if ((oldCbCount == 0) && (newCbCount > 0)) {
5071 // register binder for callbacks
5072 final IAudioService service = getService();
5073 try {
5074 service.registerRecordingCallback(mRecCb);
5075 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005076 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005077 }
5078 }
5079 } else {
5080 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5081 + "registered callback");
5082 }
5083 }
5084 }
5085
5086 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005087 * Unregister an audio recording callback previously registered with
5088 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5089 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005090 */
5091 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5092 if (cb == null) {
5093 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5094 }
5095 synchronized(mRecordCallbackLock) {
5096 if (mRecordCallbackList == null) {
5097 return;
5098 }
5099 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005100 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005101 final int newCbCount = mRecordCallbackList.size();
5102 if ((oldCbCount > 0) && (newCbCount == 0)) {
5103 // unregister binder for callbacks
5104 final IAudioService service = getService();
5105 try {
5106 service.unregisterRecordingCallback(mRecCb);
5107 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005108 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005109 }
5110 }
5111 } else {
5112 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5113 + " already unregistered or never registered");
5114 }
5115 }
5116 }
5117
5118 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005119 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005120 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005121 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005122 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005123 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005124 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005125 final IAudioService service = getService();
5126 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005127 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005128 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005129 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005130 }
5131 }
5132
5133 /**
5134 * constants for the recording events, to keep in sync
5135 * with frameworks/av/include/media/AudioPolicy.h
5136 */
5137 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005138 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005139 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005140 public static final int RECORD_CONFIG_EVENT_START = 0;
5141 /** @hide */
5142 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5143 /** @hide */
5144 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5145 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005146 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005147 /**
5148 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5149 */
5150 /** @hide */
5151 public static final int RECORD_RIID_INVALID = -1;
5152 /** @hide */
5153 public static final int RECORDER_STATE_STARTED = 0;
5154 /** @hide */
5155 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005156
5157 /**
5158 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005159 * List is lazy-initialized in
5160 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005161 * List can be null.
5162 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005163 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005164 private final Object mRecordCallbackLock = new Object();
5165
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005166 /**
5167 * Must be called synchronized on mRecordCallbackLock
5168 */
5169 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5170 if (mRecordCallbackList != null) {
5171 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5172 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5173 return true;
5174 }
5175 }
5176 }
5177 return false;
5178 }
5179
5180 /**
5181 * Must be called synchronized on mRecordCallbackLock
5182 */
5183 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5184 if (mRecordCallbackList != null) {
5185 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5186 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5187 mRecordCallbackList.remove(i);
5188 return true;
5189 }
5190 }
5191 }
5192 return false;
5193 }
5194
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005195 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005196 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005197 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005198 synchronized(mRecordCallbackLock) {
5199 if (mRecordCallbackList != null) {
5200 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5201 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5202 if (arci.mHandler != null) {
5203 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005204 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5205 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005206 arci.mHandler.sendMessage(m);
5207 }
5208 }
5209 }
5210 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005211 }
5212
5213 };
5214
5215 //=====================================================================
5216
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005217 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005218 * @hide
5219 * Reload audio settings. This method is called by Settings backup
5220 * agent when audio settings are restored and causes the AudioService
5221 * to read and apply restored settings.
5222 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005223 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005224 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005225 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005226 try {
5227 service.reloadAudioSettings();
5228 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005229 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005230 }
5231 }
5232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 /**
5234 * {@hide}
5235 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005236 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005237
5238 /**
5239 * Checks whether the phone is in silent mode, with or without vibrate.
5240 *
5241 * @return true if phone is in silent mode, with or without vibrate.
5242 *
5243 * @see #getRingerMode()
5244 *
5245 * @hide pending API Council approval
5246 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005247 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005248 public boolean isSilentMode() {
5249 int ringerMode = getRingerMode();
5250 boolean silentMode =
5251 (ringerMode == RINGER_MODE_SILENT) ||
5252 (ringerMode == RINGER_MODE_VIBRATE);
5253 return silentMode;
5254 }
5255
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005256 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5257 // class is not used by other parts of the framework, which instead use definitions and methods
5258 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5259
Eric Laurent948d3272014-05-16 15:18:45 -07005260 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005261 * The audio device code for representing "no device." */
5262 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5263 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005264 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005265 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5266 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5267 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5268 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005269 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005270 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005271 /** @hide
5272 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005273 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005274 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005275 /** @hide
5276 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005277 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005278 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005279 /** @hide
5280 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005281 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005282 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005283 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005284 * The audio output device code for a USB headphone with attached microphone */
5285 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5286 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005287 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005288 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005289 /** @hide
5290 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5291 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005292 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005293 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005294 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5295 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005296 /** @hide
5297 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005298 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5299 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005300 /** @hide
5301 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005302 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005303 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005304 /** @hide
5305 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005306 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005307 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5308 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005309 /** @hide
5310 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005311 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005312 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5313 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005314 /** @hide
5315 * The audio output device code for S/PDIF (legacy) or HDMI
5316 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005317 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005318 /** @hide
5319 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005320 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005321 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5322 /** @hide
5323 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005324 * docking station
5325 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005326 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005327 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005328 /** @hide
5329 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005330 * docking station
5331 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005332 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005333 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005334 /** @hide
5335 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005336 * mode and the Android device in USB device mode
5337 */
5338 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005339 /** @hide
5340 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005341 * mode and the Android device in USB host mode
5342 */
5343 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005344 /** @hide
5345 * The audio output device code for projection output.
5346 */
5347 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5348 /** @hide
5349 * The audio output device code the telephony voice TX path.
5350 */
5351 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5352 /** @hide
5353 * The audio output device code for an analog jack with line impedance detected.
5354 */
5355 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5356 /** @hide
5357 * The audio output device code for HDMI Audio Return Channel.
5358 */
5359 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5360 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005361 * The audio output device code for HDMI enhanced Audio Return Channel.
5362 */
5363 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5364 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005365 * The audio output device code for S/PDIF digital connection.
5366 */
5367 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5368 /** @hide
5369 * The audio output device code for built-in FM transmitter.
5370 */
5371 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5372 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005373 * The audio output device code for echo reference injection point.
5374 */
5375 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5376 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005377 * The audio output device code for a BLE audio headset.
5378 */
5379 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5380 /** @hide
5381 * The audio output device code for a BLE audio speaker.
5382 */
5383 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5384 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005385 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005386 * used in the future in a set method to select whatever default device is chosen by the
5387 * platform-specific implementation.
5388 */
5389 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5390
Eric Laurent948d3272014-05-16 15:18:45 -07005391 /** @hide
5392 * The audio input device code for default built-in microphone
5393 */
5394 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5395 /** @hide
5396 * The audio input device code for a Bluetooth SCO headset
5397 */
5398 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5399 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5400 /** @hide
5401 * The audio input device code for wired headset microphone
5402 */
5403 public static final int DEVICE_IN_WIRED_HEADSET =
5404 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5405 /** @hide
5406 * The audio input device code for HDMI
5407 */
5408 public static final int DEVICE_IN_HDMI =
5409 AudioSystem.DEVICE_IN_HDMI;
5410 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005411 * The audio input device code for HDMI ARC
5412 */
5413 public static final int DEVICE_IN_HDMI_ARC =
5414 AudioSystem.DEVICE_IN_HDMI_ARC;
5415
5416 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005417 * The audio input device code for HDMI EARC
5418 */
5419 public static final int DEVICE_IN_HDMI_EARC =
5420 AudioSystem.DEVICE_IN_HDMI_EARC;
5421
5422 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005423 * The audio input device code for telephony voice RX path
5424 */
5425 public static final int DEVICE_IN_TELEPHONY_RX =
5426 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5427 /** @hide
5428 * The audio input device code for built-in microphone pointing to the back
5429 */
5430 public static final int DEVICE_IN_BACK_MIC =
5431 AudioSystem.DEVICE_IN_BACK_MIC;
5432 /** @hide
5433 * The audio input device code for analog from a docking station
5434 */
5435 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5436 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5437 /** @hide
5438 * The audio input device code for digital from a docking station
5439 */
5440 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5441 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5442 /** @hide
5443 * The audio input device code for a USB audio accessory. The accessory is in USB host
5444 * mode and the Android device in USB device mode
5445 */
5446 public static final int DEVICE_IN_USB_ACCESSORY =
5447 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5448 /** @hide
5449 * The audio input device code for a USB audio device. The device is in USB device
5450 * mode and the Android device in USB host mode
5451 */
5452 public static final int DEVICE_IN_USB_DEVICE =
5453 AudioSystem.DEVICE_IN_USB_DEVICE;
5454 /** @hide
5455 * The audio input device code for a FM radio tuner
5456 */
5457 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5458 /** @hide
5459 * The audio input device code for a TV tuner
5460 */
5461 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5462 /** @hide
5463 * The audio input device code for an analog jack with line impedance detected
5464 */
5465 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5466 /** @hide
5467 * The audio input device code for a S/PDIF digital connection
5468 */
5469 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005470 /** @hide
5471 * The audio input device code for audio loopback
5472 */
5473 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005474 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005475 * The audio input device code for an echo reference capture point.
5476 */
5477 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5478 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005479 * The audio input device code for a BLE audio headset.
5480 */
5481 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005482
5483 /**
5484 * Return true if the device code corresponds to an output device.
5485 * @hide
5486 */
5487 public static boolean isOutputDevice(int device)
5488 {
5489 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5490 }
5491
5492 /**
5493 * Return true if the device code corresponds to an input device.
5494 * @hide
5495 */
5496 public static boolean isInputDevice(int device)
5497 {
5498 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5499 }
5500
5501
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005502 /**
5503 * Return the enabled devices for the specified output stream type.
5504 *
5505 * @param streamType The stream type to query. One of
5506 * {@link #STREAM_VOICE_CALL},
5507 * {@link #STREAM_SYSTEM},
5508 * {@link #STREAM_RING},
5509 * {@link #STREAM_MUSIC},
5510 * {@link #STREAM_ALARM},
5511 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005512 * {@link #STREAM_DTMF},
5513 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005514 *
5515 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5516 * stream. Zero or more of
5517 * {@link #DEVICE_OUT_EARPIECE},
5518 * {@link #DEVICE_OUT_SPEAKER},
5519 * {@link #DEVICE_OUT_WIRED_HEADSET},
5520 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5521 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5522 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5523 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5524 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5525 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5526 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005527 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005528 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5529 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005530 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5531 * {@link #DEVICE_OUT_USB_DEVICE}.
5532 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5533 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5534 * {@link #DEVICE_OUT_LINE}.
5535 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005536 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005537 * {@link #DEVICE_OUT_SPDIF}.
5538 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005539 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5540 *
5541 * The implementation may support additional device codes beyond those listed, so
5542 * the application should ignore any bits which it does not recognize.
5543 * Note that the information may be imprecise when the implementation
5544 * cannot distinguish whether a particular device is enabled.
5545 *
5546 * {@hide}
5547 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005548 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005549 public int getDevicesForStream(int streamType) {
5550 switch (streamType) {
5551 case STREAM_VOICE_CALL:
5552 case STREAM_SYSTEM:
5553 case STREAM_RING:
5554 case STREAM_MUSIC:
5555 case STREAM_ALARM:
5556 case STREAM_NOTIFICATION:
5557 case STREAM_DTMF:
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005558 case STREAM_ACCESSIBILITY:
Eric Laurent89c3a972020-12-16 15:57:56 +01005559 final IAudioService service = getService();
5560 try {
5561 return service.getDevicesForStream(streamType);
5562 } catch (RemoteException e) {
5563 throw e.rethrowFromSystemServer();
5564 }
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005565 default:
5566 return 0;
5567 }
5568 }
5569
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005570 /**
5571 * @hide
5572 * Get the audio devices that would be used for the routing of the given audio attributes.
5573 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5574 * @return an empty list if there was an issue with the request, a list of audio devices
5575 * otherwise (typically one device, except for duplicated paths).
5576 */
5577 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005578 @RequiresPermission(anyOf = {
5579 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5580 android.Manifest.permission.QUERY_AUDIO_STATE
5581 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005582 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005583 @NonNull AudioAttributes attributes) {
5584 Objects.requireNonNull(attributes);
5585 final IAudioService service = getService();
5586 try {
5587 return service.getDevicesForAttributes(attributes);
5588 } catch (RemoteException e) {
5589 throw e.rethrowFromSystemServer();
5590 }
5591 }
5592
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005593 /**
5594 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005595 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02005596 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5597 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005598 */
5599 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5600 /**
5601 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005602 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02005603 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005604 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005605 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005606 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5607 /**
5608 * @hide
5609 * Volume behavior for an audio device where the volume is always set to provide no attenuation
5610 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005611 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005612 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005613 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005614 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5615 /**
5616 * @hide
5617 * Volume behavior for an audio device where the volume is either set to muted, or to provide
5618 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005619 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005620 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005621 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005622 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5623 /**
5624 * @hide
5625 * Volume behavior for an audio device where no software attenuation is applied, and
5626 * the volume is kept synchronized between the host and the device itself through a
5627 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005628 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005629 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005630 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005631 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5632 /**
5633 * @hide
5634 * Volume behavior for an audio device where no software attenuation is applied, and
5635 * the volume is kept synchronized between the host and the device itself through a
5636 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5637 * normal vs in phone call).
5638 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02005639 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005640 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005641 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005642 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5643
5644 /** @hide */
5645 @IntDef({
5646 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5647 DEVICE_VOLUME_BEHAVIOR_FULL,
5648 DEVICE_VOLUME_BEHAVIOR_FIXED,
5649 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5650 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5651 })
5652 @Retention(RetentionPolicy.SOURCE)
5653 public @interface DeviceVolumeBehavior {}
5654
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005655 /** @hide */
5656 @IntDef({
5657 DEVICE_VOLUME_BEHAVIOR_UNSET,
5658 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5659 DEVICE_VOLUME_BEHAVIOR_FULL,
5660 DEVICE_VOLUME_BEHAVIOR_FIXED,
5661 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5662 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5663 })
5664 @Retention(RetentionPolicy.SOURCE)
5665 public @interface DeviceVolumeBehaviorState {}
5666
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005667 /**
5668 * @hide
5669 * Throws IAE on an invalid volume behavior value
5670 * @param volumeBehavior behavior value to check
5671 */
5672 public static void enforceValidVolumeBehavior(int volumeBehavior) {
5673 switch (volumeBehavior) {
5674 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5675 case DEVICE_VOLUME_BEHAVIOR_FULL:
5676 case DEVICE_VOLUME_BEHAVIOR_FIXED:
5677 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5678 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5679 return;
5680 default:
5681 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5682 }
5683 }
5684
5685 /**
5686 * @hide
5687 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005688 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5689 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5690 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5691 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5692 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5693 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005694 * @param deviceVolumeBehavior one of the device behaviors
5695 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005696 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005697 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5698 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5699 @DeviceVolumeBehavior int deviceVolumeBehavior) {
5700 // verify arguments (validity of device type is enforced in server)
5701 Objects.requireNonNull(device);
5702 enforceValidVolumeBehavior(deviceVolumeBehavior);
5703 // communicate with service
5704 final IAudioService service = getService();
5705 try {
5706 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5707 mApplicationContext.getOpPackageName());
5708 } catch (RemoteException e) {
5709 throw e.rethrowFromSystemServer();
5710 }
5711 }
5712
5713 /**
5714 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005715 * Returns the volume device behavior for the given audio device
5716 * @param device the audio device
5717 * @return the volume behavior for the device
5718 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005719 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005720 @RequiresPermission(anyOf = {
5721 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5722 android.Manifest.permission.QUERY_AUDIO_STATE
5723 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02005724 public @DeviceVolumeBehavior
5725 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005726 // verify arguments (validity of device type is enforced in server)
5727 Objects.requireNonNull(device);
5728 // communicate with service
5729 final IAudioService service = getService();
5730 try {
5731 return service.getDeviceVolumeBehavior(device);
5732 } catch (RemoteException e) {
5733 throw e.rethrowFromSystemServer();
5734 }
5735 }
5736
kholoud mohamed37839212021-03-15 16:49:06 +00005737 /**
5738 * @hide
5739 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5740 */
5741 @TestApi
5742 @RequiresPermission(anyOf = {
5743 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5744 android.Manifest.permission.QUERY_AUDIO_STATE
5745 })
5746 public boolean isFullVolumeDevice() {
5747 final AudioAttributes attributes = new AudioAttributes.Builder()
5748 .setUsage(AudioAttributes.USAGE_MEDIA)
5749 .build();
5750 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5751 for (AudioDeviceAttributes device : devices) {
5752 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5753 return true;
5754 }
5755 }
5756 return false;
5757 }
5758
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005759 /**
5760 * Indicate wired accessory connection state change.
5761 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5762 * @param state new connection state: 1 connected, 0 disconnected
5763 * @param name device name
5764 * {@hide}
5765 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005766 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07005767 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul McLean10804eb2015-01-28 11:16:35 -08005768 public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005769 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005770 try {
John Spurlock90874332015-03-10 16:00:54 -04005771 service.setWiredDeviceConnectionState(type, state, address, name,
Marco Nelissena80ac052015-03-12 16:17:45 -07005772 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005773 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005774 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005775 }
5776 }
5777
Grzegorz Kołodziejczyk59b2baa2021-05-14 12:19:07 +00005778 /**
Jean-Michel Trivi4da775d2021-12-03 15:33:46 -08005779 * Indicate wired accessory connection state change.
5780 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
5781 * @param connected true for connected, false for disconnected
5782 * {@hide}
5783 */
5784 @TestApi
5785 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5786 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
5787 boolean connected) {
5788 try {
5789 getService().setTestDeviceConnectionState(device, connected);
5790 } catch (RemoteException e) {
5791 throw e.rethrowFromSystemServer();
5792 }
5793 }
5794
5795 /**
wescande7c17ba0c2021-07-30 16:46:14 +02005796 * Indicate Bluetooth profile connection state change.
5797 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
5798 * <code>previousDevice</code>
5799 * This operation is asynchronous.
5800 *
5801 * @param newDevice Bluetooth device connected or null if there is no new devices
5802 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
5803 * devices
5804 * @param info contain all info related to the device. {@link BtProfileConnectionInfo}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005805 * {@hide}
5806 */
wescande7c17ba0c2021-07-30 16:46:14 +02005807 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
5808 @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
5809 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
5810 @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005811 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005812 try {
wescande7c17ba0c2021-07-30 16:46:14 +02005813 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005814 } catch (RemoteException e) {
5815 throw e.rethrowFromSystemServer();
5816 }
5817 }
5818
Jeff Sharkey098d5802012-04-26 17:30:34 -07005819 /** {@hide} */
5820 public IRingtonePlayer getRingtonePlayer() {
5821 try {
5822 return getService().getRingtonePlayer();
5823 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005824 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005825 }
5826 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005827
5828 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005829 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07005830 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
5831 * should use this value as a default, and offer the user the option to override it.
5832 * The low latency output stream is typically either the device's primary output stream,
5833 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005834 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005835 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005836 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5837 "android.media.property.OUTPUT_SAMPLE_RATE";
5838
5839 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005840 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07005841 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
5842 * should use this value as a minimum, and offer the user the option to override it.
5843 * The low latency output stream is typically either the device's primary output stream,
5844 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005845 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005846 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005847 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
5848 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
5849
5850 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07005851 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
5852 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5853 */
5854 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
5855 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
5856
5857 /**
5858 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
5859 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5860 */
5861 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
5862 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
5863
5864 /**
ragoa7cc59c2015-12-02 11:31:15 -08005865 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
5866 * available and supported with the expected frequency range and level response.
5867 */
5868 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
5869 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
5870 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005871 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07005872 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07005873 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
5874 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08005875 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
5876 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
5877 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07005878 * @return A string representing the associated value for that property key,
5879 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07005880 */
5881 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07005882 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
5883 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
5884 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
5885 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
5886 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
5887 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07005888 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07005889 // Will throw a RuntimeException Resources.NotFoundException if this config value is
5890 // not found.
5891 return String.valueOf(getContext().getResources().getBoolean(
5892 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07005893 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07005894 return String.valueOf(getContext().getResources().getBoolean(
5895 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08005896 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
5897 return String.valueOf(getContext().getResources().getBoolean(
5898 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07005899 } else {
5900 // null or unknown key
5901 return null;
5902 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005903 }
5904
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005905 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08005906 * @hide
5907 * Sets an additional audio output device delay in milliseconds.
5908 *
5909 * The additional output delay is a request to the output device to
5910 * delay audio presentation (generally with respect to video presentation for better
5911 * synchronization).
5912 * It may not be supported by all output devices,
5913 * and typically increases the audio latency by the amount of additional
5914 * audio delay requested.
5915 *
5916 * If additional audio delay is supported by an audio output device,
5917 * it is expected to be supported for all output streams (and configurations)
5918 * opened on that device.
5919 *
5920 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07005921 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08005922 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
5923 * @return true if successful, false if the device does not support output device delay
5924 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
5925 */
5926 @SystemApi
5927 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5928 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07005929 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005930 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005931 try {
5932 return getService().setAdditionalOutputDeviceDelay(
5933 new AudioDeviceAttributes(device), delayMillis);
5934 } catch (RemoteException e) {
5935 throw e.rethrowFromSystemServer();
5936 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005937 }
5938
5939 /**
5940 * @hide
5941 * Returns the current additional audio output device delay in milliseconds.
5942 *
5943 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5944 * @return the additional output device delay. This is a non-negative number.
5945 * {@code 0} is returned if unsupported.
5946 */
5947 @SystemApi
5948 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07005949 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005950 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005951 try {
5952 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
5953 } catch (RemoteException e) {
5954 throw e.rethrowFromSystemServer();
5955 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005956 }
5957
5958 /**
5959 * @hide
5960 * Returns the maximum additional audio output device delay in milliseconds.
5961 *
5962 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5963 * @return the maximum output device delay in milliseconds that can be set.
5964 * This is a non-negative number
5965 * representing the additional audio delay supported for the device.
5966 * {@code 0} is returned if unsupported.
5967 */
5968 @SystemApi
5969 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07005970 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005971 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005972 try {
5973 return getService().getMaxAdditionalOutputDeviceDelay(
5974 new AudioDeviceAttributes(device));
5975 } catch (RemoteException e) {
5976 throw e.rethrowFromSystemServer();
5977 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005978 }
5979
5980 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005981 * Returns the estimated latency for the given stream type in milliseconds.
5982 *
5983 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
5984 * a better solution.
5985 * @hide
5986 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005987 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005988 public int getOutputLatency(int streamType) {
5989 return AudioSystem.getOutputLatency(streamType);
5990 }
5991
John Spurlock3346a802014-05-20 16:25:37 -04005992 /**
5993 * Registers a global volume controller interface. Currently limited to SystemUI.
5994 *
5995 * @hide
5996 */
5997 public void setVolumeController(IVolumeController controller) {
5998 try {
5999 getService().setVolumeController(controller);
6000 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006001 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006002 }
6003 }
6004
6005 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006006 * Notify audio manager about volume controller visibility changes.
6007 * Currently limited to SystemUI.
6008 *
6009 * @hide
6010 */
6011 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6012 try {
6013 getService().notifyVolumeControllerVisible(controller, visible);
6014 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006015 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006016 }
6017 }
6018
6019 /**
John Spurlock3346a802014-05-20 16:25:37 -04006020 * Only useful for volume controllers.
6021 * @hide
6022 */
John Spurlock3346a802014-05-20 16:25:37 -04006023 public boolean isStreamAffectedByRingerMode(int streamType) {
6024 try {
6025 return getService().isStreamAffectedByRingerMode(streamType);
6026 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006027 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006028 }
6029 }
6030
6031 /**
6032 * Only useful for volume controllers.
6033 * @hide
6034 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006035 public boolean isStreamAffectedByMute(int streamType) {
6036 try {
6037 return getService().isStreamAffectedByMute(streamType);
6038 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006039 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006040 }
6041 }
6042
6043 /**
6044 * Only useful for volume controllers.
6045 * @hide
6046 */
John Spurlock3346a802014-05-20 16:25:37 -04006047 public void disableSafeMediaVolume() {
6048 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006049 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006050 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006051 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006052 }
6053 }
Eric Laurenta198a292014-02-18 16:26:17 -08006054
6055 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006056 * Only useful for volume controllers.
6057 * @hide
6058 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006059 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006060 public void setRingerModeInternal(int ringerMode) {
6061 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006062 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006063 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006064 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006065 }
6066 }
6067
6068 /**
6069 * Only useful for volume controllers.
6070 * @hide
6071 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006072 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006073 public int getRingerModeInternal() {
6074 try {
6075 return getService().getRingerModeInternal();
6076 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006077 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006078 }
6079 }
6080
6081 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006082 * Only useful for volume controllers.
6083 * @hide
6084 */
6085 public void setVolumePolicy(VolumePolicy policy) {
6086 try {
6087 getService().setVolumePolicy(policy);
6088 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006089 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006090 }
6091 }
6092
6093 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006094 * Set Hdmi Cec system audio mode.
6095 *
6096 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006097 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006098 * @hide
6099 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006100 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006101 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006102 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006103 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006104 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006105 }
6106 }
6107
6108 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006109 * Returns true if Hdmi Cec system audio mode is supported.
6110 *
6111 * @hide
6112 */
6113 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006114 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006115 public boolean isHdmiSystemAudioSupported() {
6116 try {
6117 return getService().isHdmiSystemAudioSupported();
6118 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006119 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006120 }
6121 }
6122
6123 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006124 * Return codes for listAudioPorts(), createAudioPatch() ...
6125 */
6126
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006127 /** @hide */
6128 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006129 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006130 /**
6131 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006132 */
6133 public static final int ERROR = AudioSystem.ERROR;
6134 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006135 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006136 */
6137 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6138 /** @hide
6139 */
6140 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6141 /** @hide
6142 */
6143 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6144 /** @hide
6145 */
6146 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006147 /**
6148 * An error code indicating that the object reporting it is no longer valid and needs to
6149 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006150 */
6151 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6152
6153 /**
6154 * Returns a list of descriptors for all audio ports managed by the audio framework.
6155 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6156 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6157 * See AudioPort for a list of attributes of each audio port.
6158 * @param ports An AudioPort ArrayList where the list will be returned.
6159 * @hide
6160 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006161 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006162 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006163 return updateAudioPortCache(ports, null, null);
6164 }
6165
6166 /**
6167 * Returns a list of descriptors for all audio ports managed by the audio framework as
6168 * it was before the last update calback.
6169 * @param ports An AudioPort ArrayList where the list will be returned.
6170 * @hide
6171 */
6172 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6173 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006174 }
6175
6176 /**
6177 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6178 * @see listAudioPorts(ArrayList<AudioPort>)
6179 * @hide
6180 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006181 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006182 if (devices == null) {
6183 return ERROR_BAD_VALUE;
6184 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006185 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006186 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006187 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006188 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006189 }
6190 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006191 }
6192
6193 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006194 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6195 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6196 * @hide
6197 */
6198 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6199 if (devices == null) {
6200 return ERROR_BAD_VALUE;
6201 }
6202 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6203 int status = updateAudioPortCache(null, null, ports);
6204 if (status == SUCCESS) {
6205 filterDevicePorts(ports, devices);
6206 }
6207 return status;
6208 }
6209
6210 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6211 ArrayList<AudioDevicePort> devices) {
6212 devices.clear();
6213 for (int i = 0; i < ports.size(); i++) {
6214 if (ports.get(i) instanceof AudioDevicePort) {
6215 devices.add((AudioDevicePort)ports.get(i));
6216 }
6217 }
6218 }
6219
6220 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006221 * Create a connection between two or more devices. The framework will reject the request if
6222 * device types are not compatible or the implementation does not support the requested
6223 * configuration.
6224 * NOTE: current implementation is limited to one source and one sink per patch.
6225 * @param patch AudioPatch array where the newly created patch will be returned.
6226 * As input, if patch[0] is not null, the specified patch will be replaced by the
6227 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6228 * patch and allows the implementation to optimize transitions.
6229 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6230 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6231 *
6232 * @return - {@link #SUCCESS} if connection is successful.
6233 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6234 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6235 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6236 * a patch.
6237 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6238 * - {@link #ERROR} if patch cannot be connected for any other reason.
6239 *
6240 * patch[0] contains the newly created patch
6241 * @hide
6242 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006243 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006244 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006245 AudioPortConfig[] sources,
6246 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006247 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006248 }
6249
6250 /**
6251 * Releases an existing audio patch connection.
6252 * @param patch The audio patch to disconnect.
6253 * @return - {@link #SUCCESS} if disconnection is successful.
6254 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6255 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6256 * a patch.
6257 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6258 * - {@link #ERROR} if patch cannot be released for any other reason.
6259 * @hide
6260 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006261 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006262 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006263 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006264 }
6265
6266 /**
6267 * List all existing connections between audio ports.
6268 * @param patches An AudioPatch array where the list will be returned.
6269 * @hide
6270 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006271 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006272 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006273 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006274 }
6275
6276 /**
6277 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6278 * AudioGain.buildConfig()
6279 * @hide
6280 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006281 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006282 if (port == null || gain == null) {
6283 return ERROR_BAD_VALUE;
6284 }
6285 AudioPortConfig activeConfig = port.activeConfig();
6286 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6287 activeConfig.channelMask(), activeConfig.format(), gain);
6288 config.mConfigMask = AudioPortConfig.GAIN;
6289 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006290 }
6291
6292 /**
6293 * Listener registered by client to be notified upon new audio port connections,
6294 * disconnections or attributes update.
6295 * @hide
6296 */
6297 public interface OnAudioPortUpdateListener {
6298 /**
6299 * Callback method called upon audio port list update.
6300 * @param portList the updated list of audio ports
6301 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006302 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006303
6304 /**
6305 * Callback method called upon audio patch list update.
6306 * @param patchList the updated list of audio patches
6307 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006308 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006309
6310 /**
6311 * Callback method called when the mediaserver dies
6312 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006313 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006314 }
6315
6316 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006317 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006318 * @hide
6319 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006320 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006321 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006322 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006323 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006324 }
6325
6326 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006327 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006328 * @hide
6329 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006330 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006331 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006332 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006333 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006334
6335 //
6336 // AudioPort implementation
6337 //
6338
6339 static final int AUDIOPORT_GENERATION_INIT = 0;
Eric Laurentf076db42015-01-14 13:23:27 -08006340 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT);
6341 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006342 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurentf076db42015-01-14 13:23:27 -08006343 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006344
Eric Laurentf076db42015-01-14 13:23:27 -08006345 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006346 int generation;
Eric Laurentf076db42015-01-14 13:23:27 -08006347 synchronized (sAudioPortGeneration) {
6348 generation = sAudioPortGeneration;
6349 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006350 }
6351 return generation;
6352 }
6353
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006354 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6355 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006356 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006357 synchronized (sAudioPortGeneration) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006358
Eric Laurentf076db42015-01-14 13:23:27 -08006359 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006360 int[] patchGeneration = new int[1];
6361 int[] portGeneration = new int[1];
6362 int status;
6363 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6364 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6365
6366 do {
6367 newPorts.clear();
6368 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006369 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006370 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006371 return status;
6372 }
6373 newPatches.clear();
6374 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006375 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006376 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006377 return status;
6378 }
jiabinc4ecaa52017-09-26 14:28:41 -07006379 // Loop until patch generation is the same as port generation unless audio ports
6380 // and audio patches are not null.
6381 } while (patchGeneration[0] != portGeneration[0]
6382 && (ports == null || patches == null));
6383 // If the patch generation doesn't equal port generation, return ERROR here in case
6384 // of mismatch between audio ports and audio patches.
6385 if (patchGeneration[0] != portGeneration[0]) {
6386 return ERROR;
6387 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006388
6389 for (int i = 0; i < newPatches.size(); i++) {
6390 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006391 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6392 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006393 newPatches.get(i).sources()[j] = portCfg;
6394 }
6395 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006396 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6397 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006398 newPatches.get(i).sinks()[j] = portCfg;
6399 }
6400 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006401 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6402 AudioPatch newPatch = i.next();
6403 boolean hasInvalidPort = false;
6404 for (AudioPortConfig portCfg : newPatch.sources()) {
6405 if (portCfg == null) {
6406 hasInvalidPort = true;
6407 break;
6408 }
6409 }
6410 for (AudioPortConfig portCfg : newPatch.sinks()) {
6411 if (portCfg == null) {
6412 hasInvalidPort = true;
6413 break;
6414 }
6415 }
6416 if (hasInvalidPort) {
6417 // Temporarily remove patches with invalid ports. One who created the patch
6418 // is responsible for dealing with the port change.
6419 i.remove();
6420 }
6421 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006422
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006423 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006424 sAudioPortsCached = newPorts;
6425 sAudioPatchesCached = newPatches;
6426 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006427 }
6428 if (ports != null) {
6429 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006430 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006431 }
6432 if (patches != null) {
6433 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006434 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006435 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006436 if (previousPorts != null) {
6437 previousPorts.clear();
6438 previousPorts.addAll(sPreviousAudioPortsCached);
6439 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006440 }
6441 return SUCCESS;
6442 }
6443
Eric Laurentf076db42015-01-14 13:23:27 -08006444 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006445 AudioPort port = portCfg.port();
6446 int k;
6447 for (k = 0; k < ports.size(); k++) {
6448 // compare handles because the port returned by JNI is not of the correct
6449 // subclass
6450 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006451 port = ports.get(k);
6452 break;
6453 }
6454 }
6455 if (k == ports.size()) {
6456 // this hould never happen
6457 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
6458 return null;
6459 }
6460 AudioGainConfig gainCfg = portCfg.gain();
6461 if (gainCfg != null) {
6462 AudioGain gain = port.gain(gainCfg.index());
6463 gainCfg = gain.buildConfig(gainCfg.mode(),
6464 gainCfg.channelMask(),
6465 gainCfg.values(),
6466 gainCfg.rampDurationMs());
6467 }
6468 return port.buildConfig(portCfg.samplingRate(),
6469 portCfg.channelMask(),
6470 portCfg.format(),
6471 gainCfg);
6472 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006473
6474 private OnAmPortUpdateListener mPortListener = null;
6475
6476 /**
6477 * The message sent to apps when the contents of the device list changes if they provide
Andrew Solovay5c05ded2018-10-02 14:14:42 -07006478 * a {@link Handler} object to addOnAudioDeviceConnectionListener().
Paul McLeane3383cc2015-05-08 11:41:20 -07006479 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006480 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6481 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6482 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006483
Paul McLean8e6c9f42015-05-19 11:13:41 -07006484 /**
6485 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6486 */
Jack He89f97982018-05-02 19:10:56 -07006487 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006488 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006489
6490 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006491 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6492 * the results list to only those device types they are interested in.
6493 */
6494 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07006495 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6496 * source (i.e. input) audio devices.
6497 */
6498 public static final int GET_DEVICES_INPUTS = 0x0001;
6499
6500 /**
6501 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6502 * sink (i.e. output) audio devices.
6503 */
6504 public static final int GET_DEVICES_OUTPUTS = 0x0002;
6505
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006506 /** @hide */
6507 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6508 GET_DEVICES_INPUTS,
6509 GET_DEVICES_OUTPUTS }
6510 )
6511 @Retention(RetentionPolicy.SOURCE)
6512 public @interface AudioDeviceRole {}
6513
Paul McLeane3383cc2015-05-08 11:41:20 -07006514 /**
6515 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6516 * source and sink devices.
6517 */
6518 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6519
6520 /**
6521 * Determines if a given AudioDevicePort meets the specified filter criteria.
6522 * @param port The port to test.
6523 * @param flags A set of bitflags specifying the criteria to test.
6524 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6525 **/
6526 private static boolean checkFlags(AudioDevicePort port, int flags) {
6527 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6528 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6529 }
6530
Paul McLean11354572015-08-07 12:50:48 -06006531 private static boolean checkTypes(AudioDevicePort port) {
6532 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07006533 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06006534 }
6535
Paul McLeane3383cc2015-05-08 11:41:20 -07006536 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006537 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6538 * currently connected to the system and meeting the criteria specified in the
6539 * <code>flags</code> parameter.
Paul McLeane3383cc2015-05-08 11:41:20 -07006540 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006541 * @see #GET_DEVICES_OUTPUTS
6542 * @see #GET_DEVICES_INPUTS
6543 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07006544 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6545 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006546 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006547 return getDevicesStatic(flags);
6548 }
6549
Paul McLean8e6c9f42015-05-19 11:13:41 -07006550 /**
6551 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6552 * objects from the current (internal) AudioDevicePort list.
6553 */
Paul McLean03346882015-05-12 15:36:56 -07006554 private static AudioDeviceInfo[]
6555 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006556
Paul McLean8e6c9f42015-05-19 11:13:41 -07006557 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07006558 int numRecs = 0;
6559 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006560 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006561 numRecs++;
6562 }
6563 }
6564
Paul McLean8e6c9f42015-05-19 11:13:41 -07006565 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07006566 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6567 int slot = 0;
6568 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006569 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006570 deviceList[slot++] = new AudioDeviceInfo(port);
6571 }
6572 }
6573
6574 return deviceList;
6575 }
6576
Paul McLean03346882015-05-12 15:36:56 -07006577 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07006578 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6579 * the add/remove callback mechanism to provide a list of the newly added or removed devices
6580 * rather than the whole list and make the app figure it out.
6581 * Note that calling this method with:
6582 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6583 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07006584 */
6585 private static AudioDeviceInfo[] calcListDeltas(
6586 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6587
6588 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6589
6590 AudioDevicePort cur_port = null;
6591 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6592 boolean cur_port_found = false;
6593 cur_port = ports_B.get(cur_index);
6594 for (int prev_index = 0;
6595 prev_index < ports_A.size() && !cur_port_found;
6596 prev_index++) {
6597 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6598 }
6599
6600 if (!cur_port_found) {
6601 delta_ports.add(cur_port);
6602 }
6603 }
6604
6605 return infoListFromPortList(delta_ports, flags);
6606 }
6607
Paul McLeane3383cc2015-05-08 11:41:20 -07006608 /**
Paul McLean03346882015-05-12 15:36:56 -07006609 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6610 * connected to the system and meeting the criteria specified in the <code>flags</code>
6611 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006612 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07006613 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006614 * @see #GET_DEVICES_OUTPUTS
6615 * @see #GET_DEVICES_INPUTS
6616 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07006617 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6618 * @hide
6619 */
6620 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6621 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6622 int status = AudioManager.listAudioDevicePorts(ports);
6623 if (status != AudioManager.SUCCESS) {
6624 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07006625 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07006626 }
6627
6628 return infoListFromPortList(ports, flags);
6629 }
6630
6631 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07006632 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6633 * @param portId The audio port ID to look up for.
6634 * @param flags A set of bitflags specifying the criteria to test.
6635 * @see #GET_DEVICES_OUTPUTS
6636 * @see #GET_DEVICES_INPUTS
6637 * @see #GET_DEVICES_ALL
6638 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6639 * @hide
6640 */
6641 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6642 if (portId == 0) {
6643 return null;
6644 }
6645 AudioDeviceInfo[] devices = getDevicesStatic(flags);
6646 for (AudioDeviceInfo device : devices) {
6647 if (device.getId() == portId) {
6648 return device;
6649 }
6650 }
6651 return null;
6652 }
6653
6654 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006655 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07006656 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006657 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6658 * notifications.
6659 * @param handler Specifies the {@link Handler} object for the thread on which to execute
6660 * the callback. If <code>null</code>, the {@link Handler} associated with the main
6661 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07006662 */
Paul McLean03346882015-05-12 15:36:56 -07006663 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08006664 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07006665 synchronized (mDeviceCallbacks) {
6666 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006667 if (mDeviceCallbacks.size() == 0) {
6668 if (mPortListener == null) {
6669 mPortListener = new OnAmPortUpdateListener();
6670 }
6671 registerAudioPortUpdateListener(mPortListener);
6672 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006673 NativeEventHandlerDelegate delegate =
6674 new NativeEventHandlerDelegate(callback, handler);
6675 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07006676 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07006677 }
6678 }
6679 }
6680
6681 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006682 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07006683 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006684 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08006685 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07006686 */
Paul McLean03346882015-05-12 15:36:56 -07006687 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6688 synchronized (mDeviceCallbacks) {
6689 if (mDeviceCallbacks.containsKey(callback)) {
6690 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07006691 if (mDeviceCallbacks.size() == 0) {
6692 unregisterAudioPortUpdateListener(mPortListener);
6693 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006694 }
6695 }
6696 }
6697
jiabinc0f49442018-01-05 10:23:50 -08006698 /**
6699 * Set port id for microphones by matching device type and address.
6700 * @hide
6701 */
6702 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6703 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6704 for (int i = microphones.size() - 1; i >= 0; i--) {
6705 boolean foundPortId = false;
6706 for (AudioDeviceInfo device : devices) {
6707 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6708 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6709 microphones.get(i).setId(device.getId());
6710 foundPortId = true;
6711 break;
6712 }
6713 }
6714 if (!foundPortId) {
6715 Log.i(TAG, "Failed to find port id for device with type:"
6716 + microphones.get(i).getType() + " address:"
6717 + microphones.get(i).getAddress());
6718 microphones.remove(i);
6719 }
6720 }
6721 }
6722
6723 /**
jiabin589a2362018-02-22 16:21:53 -08006724 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6725 * @hide
6726 */
6727 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6728 int deviceType = deviceInfo.getType();
6729 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6730 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6731 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6732 : MicrophoneInfo.LOCATION_PERIPHERAL;
6733 MicrophoneInfo microphone = new MicrophoneInfo(
6734 deviceInfo.getPort().name() + deviceInfo.getId(),
6735 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6736 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6737 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6738 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6739 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6740 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6741 microphone.setId(deviceInfo.getId());
6742 return microphone;
6743 }
6744
6745 /**
jiabind0be5b22018-04-10 14:10:04 -07006746 * Add {@link MicrophoneInfo} by device information while filtering certain types.
6747 */
6748 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6749 HashSet<Integer> filterTypes) {
6750 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6751 for (AudioDeviceInfo device : devices) {
6752 if (filterTypes.contains(device.getType())) {
6753 continue;
6754 }
6755 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6756 microphones.add(microphone);
6757 }
6758 }
6759
6760 /**
jiabinc0f49442018-01-05 10:23:50 -08006761 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6762 * of all available microphones. The list is empty when no microphones are available
6763 * on the device. An error during the query will result in an IOException being thrown.
6764 *
6765 * @return a list that contains all microphones' characteristics
6766 * @throws IOException if an error occurs.
6767 */
6768 public List<MicrophoneInfo> getMicrophones() throws IOException {
6769 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6770 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006771 HashSet<Integer> filterTypes = new HashSet<>();
6772 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08006773 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07006774 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07006775 if (status != AudioManager.ERROR_INVALID_OPERATION) {
6776 Log.e(TAG, "getMicrophones failed:" + status);
6777 }
6778 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07006779 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6780 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08006781 }
6782 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006783 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6784 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08006785 return microphones;
6786 }
6787
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006788 /**
6789 * Returns a list of audio formats that corresponds to encoding formats
Patty46694212021-11-04 21:03:32 +08006790 * supported on offload path for A2DP and LE audio playback.
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006791 *
Patty46694212021-11-04 21:03:32 +08006792 * @param deviceType Indicates the target device type {@link AudioSystem.DeviceType}
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006793 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
Patty46694212021-11-04 21:03:32 +08006794 * supported for offload A2DP playback or a list of {@link BluetoothLeAudioCodecConfig}
6795 * objects containing encoding formats supported for offload LE Audio playback
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006796 * @hide
6797 */
Patty46694212021-11-04 21:03:32 +08006798 public List<?> getHwOffloadFormatsSupportedForBluetoothMedia(
6799 @AudioSystem.DeviceType int deviceType) {
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006800 ArrayList<Integer> formatsList = new ArrayList<Integer>();
Patty46694212021-11-04 21:03:32 +08006801 ArrayList<BluetoothCodecConfig> a2dpCodecConfigList = new ArrayList<BluetoothCodecConfig>();
6802 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList =
6803 new ArrayList<BluetoothLeAudioCodecConfig>();
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006804
Patty46694212021-11-04 21:03:32 +08006805 if (deviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
6806 && deviceType != AudioSystem.DEVICE_OUT_BLE_HEADSET) {
6807 throw new IllegalArgumentException(
6808 "Illegal devicetype for the getHwOffloadFormatsSupportedForBluetoothMedia");
6809 }
6810
6811 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(deviceType,
6812 formatsList);
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006813 if (status != AudioManager.SUCCESS) {
Patty46694212021-11-04 21:03:32 +08006814 Log.e(TAG, "getHwOffloadFormatsSupportedForBluetoothMedia for deviceType "
6815 + deviceType + " failed:" + status);
6816 return a2dpCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006817 }
6818
Patty46694212021-11-04 21:03:32 +08006819 if (deviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
6820 for (Integer format : formatsList) {
6821 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6822 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6823 a2dpCodecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
6824 }
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006825 }
Patty46694212021-11-04 21:03:32 +08006826 return a2dpCodecConfigList;
6827 } else if (deviceType == AudioSystem.DEVICE_OUT_BLE_HEADSET) {
6828 for (Integer format : formatsList) {
6829 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
6830 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6831 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
6832 .setCodecType(btLeAudioCodec)
6833 .build());
6834 }
6835 }
6836 return leAudioCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006837 }
Patty46694212021-11-04 21:03:32 +08006838 Log.e(TAG, "Input deviceType " + deviceType + " doesn't support.");
6839 return a2dpCodecConfigList;
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006840 }
6841
Paul McLeancbeb8a22015-06-10 08:21:27 -07006842 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
6843 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
6844 // of the ports that exist at the time of the last notification.
6845 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
6846
Paul McLeane3383cc2015-05-08 11:41:20 -07006847 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006848 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07006849 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07006850 */
jiabin8c3a7672018-05-22 15:44:21 -07006851 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07006852 int status;
6853
Paul McLeancbeb8a22015-06-10 08:21:27 -07006854 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07006855 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
6856 status = AudioManager.listAudioDevicePorts(current_ports);
6857 if (status != AudioManager.SUCCESS) {
6858 return;
6859 }
6860
Paul McLeancbeb8a22015-06-10 08:21:27 -07006861 if (handler != null) {
6862 // This is the callback for the registration, so send the current list
6863 AudioDeviceInfo[] deviceList =
6864 infoListFromPortList(current_ports, GET_DEVICES_ALL);
6865 handler.sendMessage(
6866 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
6867 } else {
6868 AudioDeviceInfo[] added_devices =
6869 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
6870 AudioDeviceInfo[] removed_devices =
6871 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07006872 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07006873 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
6874 handler = mDeviceCallbacks.valueAt(i).getHandler();
6875 if (handler != null) {
6876 if (removed_devices.length != 0) {
6877 handler.sendMessage(Message.obtain(handler,
6878 MSG_DEVICES_DEVICES_REMOVED,
6879 removed_devices));
6880 }
6881 if (added_devices.length != 0) {
6882 handler.sendMessage(Message.obtain(handler,
6883 MSG_DEVICES_DEVICES_ADDED,
6884 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07006885 }
Paul McLean03346882015-05-12 15:36:56 -07006886 }
6887 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006888 }
6889 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006890
6891 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07006892 }
6893
6894 /**
6895 * Handles Port list update notifications from the AudioManager
6896 */
6897 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
6898 static final String TAG = "OnAmPortUpdateListener";
6899 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07006900 synchronized (mDeviceCallbacks) {
6901 broadcastDeviceListChange_sync(null);
6902 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006903 }
6904
6905 /**
6906 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006907 * Note: We don't do anything with Patches at this time, so ignore this notification.
6908 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07006909 */
6910 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
6911
6912 /**
6913 * Callback method called when the mediaserver dies
6914 */
6915 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07006916 synchronized (mDeviceCallbacks) {
6917 broadcastDeviceListChange_sync(null);
6918 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006919 }
6920 }
6921
Eric Laurent1d3cdce2018-01-20 10:31:21 -08006922
6923 /**
6924 * @hide
6925 * Abstract class to receive event notification about audioserver process state.
6926 */
6927 @SystemApi
6928 public abstract static class AudioServerStateCallback {
6929 public void onAudioServerDown() { }
6930 public void onAudioServerUp() { }
6931 }
6932
6933 private Executor mAudioServerStateExec;
6934 private AudioServerStateCallback mAudioServerStateCb;
6935 private final Object mAudioServerStateCbLock = new Object();
6936
6937 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
6938 new IAudioServerStateDispatcher.Stub() {
6939 @Override
6940 public void dispatchAudioServerStateChange(boolean state) {
6941 Executor exec;
6942 AudioServerStateCallback cb;
6943
6944 synchronized (mAudioServerStateCbLock) {
6945 exec = mAudioServerStateExec;
6946 cb = mAudioServerStateCb;
6947 }
6948
6949 if ((exec == null) || (cb == null)) {
6950 return;
6951 }
6952 if (state) {
6953 exec.execute(() -> cb.onAudioServerUp());
6954 } else {
6955 exec.execute(() -> cb.onAudioServerDown());
6956 }
6957 }
6958 };
6959
6960 /**
6961 * @hide
6962 * Registers a callback for notification of audio server state changes.
6963 * @param executor {@link Executor} to handle the callbacks
6964 * @param stateCallback the callback to receive the audio server state changes
6965 * To remove the callabck, pass a null reference for both executor and stateCallback.
6966 */
6967 @SystemApi
6968 public void setAudioServerStateCallback(@NonNull Executor executor,
6969 @NonNull AudioServerStateCallback stateCallback) {
6970 if (stateCallback == null) {
6971 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
6972 }
6973 if (executor == null) {
6974 throw new IllegalArgumentException(
6975 "Illegal null Executor for the AudioServerStateCallback");
6976 }
6977
6978 synchronized (mAudioServerStateCbLock) {
6979 if (mAudioServerStateCb != null) {
6980 throw new IllegalStateException(
6981 "setAudioServerStateCallback called with already registered callabck");
6982 }
6983 final IAudioService service = getService();
6984 try {
6985 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
6986 } catch (RemoteException e) {
6987 throw e.rethrowFromSystemServer();
6988 }
6989 mAudioServerStateExec = executor;
6990 mAudioServerStateCb = stateCallback;
6991 }
6992 }
6993
6994 /**
6995 * @hide
6996 * Unregisters the callback for notification of audio server state changes.
6997 */
6998 @SystemApi
6999 public void clearAudioServerStateCallback() {
7000 synchronized (mAudioServerStateCbLock) {
7001 if (mAudioServerStateCb != null) {
7002 final IAudioService service = getService();
7003 try {
7004 service.unregisterAudioServerStateDispatcher(
7005 mAudioServerStateDispatcher);
7006 } catch (RemoteException e) {
7007 throw e.rethrowFromSystemServer();
7008 }
7009 }
7010 mAudioServerStateExec = null;
7011 mAudioServerStateCb = null;
7012 }
7013 }
7014
7015 /**
7016 * @hide
7017 * Checks if native audioservice is running or not.
7018 * @return true if native audioservice runs, false otherwise.
7019 */
7020 @SystemApi
7021 public boolean isAudioServerRunning() {
7022 final IAudioService service = getService();
7023 try {
7024 return service.isAudioServerRunning();
7025 } catch (RemoteException e) {
7026 throw e.rethrowFromSystemServer();
7027 }
7028 }
7029
jiabin39940752018-04-02 18:18:45 -07007030 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007031 * Sets the surround sound mode.
7032 *
7033 * @return true if successful, otherwise false
7034 */
7035 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
7036 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7037 try {
7038 return getService().setEncodedSurroundMode(mode);
7039 } catch (RemoteException e) {
7040 throw e.rethrowFromSystemServer();
7041 }
7042 }
7043
7044 /**
7045 * Gets the surround sound mode.
7046 *
7047 * @return true if successful, otherwise false
7048 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007049 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7050 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007051 return getService().getEncodedSurroundMode(
7052 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007053 } catch (RemoteException e) {
7054 throw e.rethrowFromSystemServer();
7055 }
7056 }
7057
7058 /**
jiabin39940752018-04-02 18:18:45 -07007059 * @hide
7060 * Returns all surround formats.
7061 * @return a map where the key is a surround format and
7062 * the value indicates the surround format is enabled or not
7063 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007064 @TestApi
7065 @NonNull
jiabin39940752018-04-02 18:18:45 -07007066 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007067 try {
7068 return getService().getSurroundFormats();
7069 } catch (RemoteException e) {
7070 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007071 }
jiabin39940752018-04-02 18:18:45 -07007072 }
7073
7074 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007075 * Sets and persists a certain surround format as enabled or not.
7076 * <p>
7077 * This API is called by TvSettings surround sound menu when user enables or disables a
7078 * surround sound format. This setting is persisted as global user setting.
7079 * Applications should revert their changes to surround sound settings unless they intend to
7080 * modify the global user settings across all apps. The framework does not auto-revert an
7081 * application's settings after a lifecycle event. Audio focus is not required to apply these
7082 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007083 *
jiabin39940752018-04-02 18:18:45 -07007084 * @param enabled the required surround format state, true for enabled, false for disabled
7085 * @return true if successful, otherwise false
7086 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007087 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007088 public boolean setSurroundFormatEnabled(
7089 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007090 try {
7091 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7092 } catch (RemoteException e) {
7093 throw e.rethrowFromSystemServer();
7094 }
7095 }
7096
7097 /**
7098 * Gets whether a certain surround format is enabled or not.
7099 * @param audioFormat a surround format
7100 *
7101 * @return whether the required surround format is enabled
7102 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007103 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7104 try {
7105 return getService().isSurroundFormatEnabled(audioFormat);
7106 } catch (RemoteException e) {
7107 throw e.rethrowFromSystemServer();
7108 }
jiabin39940752018-04-02 18:18:45 -07007109 }
7110
7111 /**
7112 * @hide
7113 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007114 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007115 *
Kriti Dang01924232021-03-02 13:51:09 +01007116 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007117 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007118 @TestApi
7119 @NonNull
7120 public List<Integer> getReportedSurroundFormats() {
7121 try {
7122 return getService().getReportedSurroundFormats();
7123 } catch (RemoteException e) {
7124 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007125 }
jiabin39940752018-04-02 18:18:45 -07007126 }
7127
jiabin66f9e722018-11-02 16:20:19 -07007128 /**
7129 * Return if audio haptic coupled playback is supported or not.
7130 *
7131 * @return whether audio haptic playback supported.
7132 */
7133 public static boolean isHapticPlaybackSupported() {
7134 return AudioSystem.isHapticPlaybackSupported();
7135 }
7136
François Gaffie0699fec2018-07-09 14:35:10 +02007137 /**
7138 * @hide
7139 * Introspection API to retrieve audio product strategies.
7140 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7141 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7142 * by OEM without any needs of AOSP patches.
7143 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7144 * strategy refered either by its index or human readable string. It will allow clients
7145 * application to start streaming data using these {@link AudioAttributes} on the selected
7146 * device by Audio Policy Engine.
7147 * @return a (possibly zero-length) array of
7148 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7149 */
7150 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007151 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007152 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007153 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007154 final IAudioService service = getService();
7155 try {
7156 return service.getAudioProductStrategies();
7157 } catch (RemoteException e) {
7158 throw e.rethrowFromSystemServer();
7159 }
7160 }
7161
François Gaffieadcd00a2018-09-18 17:06:26 +02007162 /**
7163 * @hide
7164 * Introspection API to retrieve audio volume groups.
7165 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7166 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007167 * @return a (possibly zero-length) List of
7168 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007169 */
7170 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007171 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007172 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007173 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007174 final IAudioService service = getService();
7175 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007176 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007177 } catch (RemoteException e) {
7178 throw e.rethrowFromSystemServer();
7179 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007180 }
7181
7182 /**
7183 * @hide
7184 * Callback registered by client to be notified upon volume group change.
7185 */
7186 @SystemApi
7187 public abstract static class VolumeGroupCallback {
7188 /**
7189 * Callback method called upon audio volume group change.
7190 * @param group the group for which the volume has changed
7191 */
7192 public void onAudioVolumeGroupChanged(int group, int flags) {}
7193 }
7194
7195 /**
7196 * @hide
7197 * Register an audio volume group change listener.
7198 * @param callback the {@link VolumeGroupCallback} to register
7199 */
7200 @SystemApi
7201 public void registerVolumeGroupCallback(
7202 @NonNull Executor executor,
7203 @NonNull VolumeGroupCallback callback) {
7204 Preconditions.checkNotNull(executor, "executor must not be null");
7205 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7206 sAudioAudioVolumeGroupChangedHandler.init();
7207 // TODO: make use of executor
7208 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7209 }
7210
7211 /**
7212 * @hide
7213 * Unregister an audio volume group change listener.
7214 * @param callback the {@link VolumeGroupCallback} to unregister
7215 */
7216 @SystemApi
7217 public void unregisterVolumeGroupCallback(
7218 @NonNull VolumeGroupCallback callback) {
7219 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7220 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7221 }
jiabin39940752018-04-02 18:18:45 -07007222
jiabinad225202019-03-20 15:22:50 -07007223 /**
7224 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007225 *
7226 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007227 * @param uri the {@link Uri} of the asset.
7228 * @return true if the assert contains haptic channels.
7229 * @hide
7230 */
jiabincfcf1032021-07-01 16:30:50 -07007231 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7232 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007233 try {
jiabincfcf1032021-07-01 16:30:50 -07007234 extractor.setDataSource(context, uri, null);
7235 for (int i = 0; i < extractor.getTrackCount(); i++) {
7236 MediaFormat format = extractor.getTrackFormat(i);
7237 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7238 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7239 return true;
7240 }
7241 }
7242 } catch (IOException e) {
7243 Log.e(TAG, "hasHapticChannels failure:" + e);
7244 }
7245 return false;
7246 }
7247
7248 /**
7249 * Return if an asset contains haptic channels or not.
7250 *
7251 * @param context the {@link Context} to resolve the uri.
7252 * @param uri the {@link Uri} of the asset.
7253 * @return true if the assert contains haptic channels.
7254 * @hide
7255 */
7256 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7257 Objects.requireNonNull(uri);
jiabin0f3339c2021-07-09 11:50:07 -07007258
jiabincfcf1032021-07-01 16:30:50 -07007259 if (context != null) {
7260 return hasHapticChannelsImpl(context, uri);
jiabin0f3339c2021-07-09 11:50:07 -07007261 }
7262
7263 Context cachedContext = sContext.get();
7264 if (cachedContext != null) {
jiabincfcf1032021-07-01 16:30:50 -07007265 if (DEBUG) {
7266 Log.d(TAG, "Try to use static context to query if having haptic channels");
7267 }
jiabin0f3339c2021-07-09 11:50:07 -07007268 return hasHapticChannelsImpl(cachedContext, uri);
7269 }
7270
7271 // Try with audio service context, this may fail to get correct result.
7272 if (DEBUG) {
7273 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7274 }
7275 try {
7276 return getService().hasHapticChannels(uri);
7277 } catch (RemoteException e) {
7278 throw e.rethrowFromSystemServer();
jiabinad225202019-03-20 15:22:50 -07007279 }
7280 }
7281
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007282 /**
7283 * Set whether or not there is an active RTT call.
7284 * This method should be called by Telecom service.
7285 * @hide
7286 * TODO: make this a @SystemApi
7287 */
7288 public static void setRttEnabled(boolean rttEnabled) {
7289 try {
7290 getService().setRttEnabled(rttEnabled);
7291 } catch (RemoteException e) {
7292 throw e.rethrowFromSystemServer();
7293 }
7294 }
7295
Jin Seok Park16aeba382020-08-06 12:52:54 +09007296 /**
7297 * Adjusts the volume of the most relevant stream, or the given fallback
7298 * stream.
7299 * <p>
7300 * This method should only be used by applications that replace the
7301 * platform-wide management of audio settings or the main telephony
7302 * application.
7303 * <p>
7304 * This method has no effect if the device implements a fixed volume policy
7305 * as indicated by {@link #isVolumeFixed()}.
7306 * <p>This API checks if the caller has the necessary permissions based on the provided
7307 * component name, uid, and pid values.
7308 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7309 *
7310 * @param suggestedStreamType The stream type that will be used if there
7311 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7312 * valid here.
7313 * @param direction The direction to adjust the volume. One of
7314 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7315 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7316 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7317 * @param flags One or more flags.
7318 * @param packageName the package name of client application
7319 * @param uid the uid of client application
7320 * @param pid the pid of client application
7321 * @param targetSdkVersion the target sdk version of client application
7322 * @see #adjustVolume(int, int)
7323 * @see #adjustStreamVolume(int, int, int)
7324 * @see #setStreamVolume(int, int, int)
7325 * @see #isVolumeFixed()
7326 *
7327 * @hide
7328 */
7329 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7330 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7331 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7332 try {
7333 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7334 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7335 } catch (RemoteException e) {
7336 throw e.rethrowFromSystemServer();
7337 }
7338 }
7339
7340 /**
7341 * Adjusts the volume of a particular stream by one step in a direction.
7342 * <p>
7343 * This method should only be used by applications that replace the platform-wide
7344 * management of audio settings or the main telephony application.
7345 * <p>This method has no effect if the device implements a fixed volume policy
7346 * as indicated by {@link #isVolumeFixed()}.
7347 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7348 * unless the app has been granted Do Not Disturb Access.
7349 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7350 * <p>This API checks if the caller has the necessary permissions based on the provided
7351 * component name, uid, and pid values.
7352 * See {@link #adjustStreamVolume(int, int, int)}.
7353 *
7354 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7355 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7356 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7357 * @param direction The direction to adjust the volume. One of
7358 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7359 * {@link #ADJUST_SAME}.
7360 * @param flags One or more flags.
7361 * @param packageName the package name of client application
7362 * @param uid the uid of client application
7363 * @param pid the pid of client application
7364 * @param targetSdkVersion the target sdk version of client application
7365 * @see #adjustVolume(int, int)
7366 * @see #setStreamVolume(int, int, int)
7367 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7368 * and the caller is not granted notification policy access.
7369 *
7370 * @hide
7371 */
7372 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7373 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7374 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7375 try {
7376 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7377 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7378 } catch (RemoteException e) {
7379 throw e.rethrowFromSystemServer();
7380 }
7381 }
7382
7383 /**
7384 * Sets the volume index for a particular stream.
7385 * <p>This method has no effect if the device implements a fixed volume policy
7386 * as indicated by {@link #isVolumeFixed()}.
7387 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7388 * the app has been granted Do Not Disturb Access.
7389 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7390 * <p>This API checks if the caller has the necessary permissions based on the provided
7391 * component name, uid, and pid values.
7392 * See {@link #setStreamVolume(int, int, int)}.
7393 *
7394 * @param streamType The stream whose volume index should be set.
7395 * @param index The volume index to set. See
7396 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7397 * @param flags One or more flags.
7398 * @param packageName the package name of client application
7399 * @param uid the uid of client application
7400 * @param pid the pid of client application
7401 * @param targetSdkVersion the target sdk version of client application
7402 * @see #getStreamMaxVolume(int)
7403 * @see #getStreamVolume(int)
7404 * @see #isVolumeFixed()
7405 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7406 * and the caller is not granted notification policy access.
7407 *
7408 * @hide
7409 */
7410 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7411 public void setStreamVolumeForUid(int streamType, int index, int flags,
7412 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7413 try {
7414 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7415 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7416 } catch (RemoteException e) {
7417 throw e.rethrowFromSystemServer();
7418 }
7419 }
7420
7421
hjin81.lee4e984e52019-12-05 14:34:52 +09007422 /** @hide
7423 * TODO: make this a @SystemApi */
7424 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7425 public void setMultiAudioFocusEnabled(boolean enabled) {
7426 try {
7427 getService().setMultiAudioFocusEnabled(enabled);
7428 } catch (RemoteException e) {
7429 throw e.rethrowFromSystemServer();
7430 }
7431 }
7432
Eric Laurent43a78de2020-07-24 17:11:15 -07007433
7434 /**
7435 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7436 * For more details on Hardware A/V synchronization please refer to
7437 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7438 * media tunneling documentation</a>.
7439 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7440 * @return the HW A/V sync ID for this audio session (an integer different from 0).
7441 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7442 */
7443 public int getAudioHwSyncForSession(int sessionId) {
7444 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7445 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7446 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7447 }
7448 return hwSyncId;
7449 }
7450
Eric Laurentb36d4a12020-10-09 09:52:49 -07007451 /**
7452 * Selects the audio device that should be used for communication use cases, for instance voice
7453 * or video calls. This method can be used by voice or video chat applications to select a
7454 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01007455 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7456 * {@link #getAvailableCommunicationDevices()}.
7457 * The selection is active as long as the requesting application process lives, until
7458 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007459 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01007460 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007461 * <p>In case of simultaneous requests by multiple applications the priority is given to the
7462 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7463 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7464 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7465 * telephony application with permission
7466 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7467 * <p> If the requested devices is not currently available, the request will be rejected and
7468 * the method will return false.
7469 * <p>This API replaces the following deprecated APIs:
7470 * <ul>
7471 * <li> {@link #startBluetoothSco()}
7472 * <li> {@link #stopBluetoothSco()}
7473 * <li> {@link #setSpeakerphoneOn(boolean)}
7474 * </ul>
7475 * <h4>Example</h4>
7476 * <p>The example below shows how to enable and disable speakerphone mode.
7477 * <pre class="prettyprint">
7478 * // Get an AudioManager instance
7479 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01007480 * AudioDeviceInfo speakerDevice = null;
7481 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7482 * for (AudioDeviceInfo device : devices) {
7483 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7484 * speakerDevice = device;
7485 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007486 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007487 * }
7488 * if (speakerDevice != null) {
7489 * // Turn speakerphone ON.
7490 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
7491 * if (!result) {
7492 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007493 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007494 * // Turn speakerphone OFF.
7495 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007496 * }
7497 * </pre>
7498 * @param device the requested audio device.
7499 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7500 * @throws IllegalArgumentException If an invalid device is specified.
7501 */
Eric Laurent7412f572021-02-11 15:10:31 +01007502 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007503 Objects.requireNonNull(device);
7504 try {
7505 if (device.getId() == 0) {
7506 throw new IllegalArgumentException("In valid device: " + device);
7507 }
Eric Laurent7412f572021-02-11 15:10:31 +01007508 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007509 } catch (RemoteException e) {
7510 throw e.rethrowFromSystemServer();
7511 }
7512 }
7513
7514 /**
7515 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01007516 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007517 */
Eric Laurent7412f572021-02-11 15:10:31 +01007518 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007519 try {
Eric Laurent7412f572021-02-11 15:10:31 +01007520 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007521 } catch (RemoteException e) {
7522 throw e.rethrowFromSystemServer();
7523 }
7524 }
7525
7526 /**
7527 * Returns currently selected audio device for communication.
7528 * <p>This API replaces the following deprecated APIs:
7529 * <ul>
7530 * <li> {@link #isBluetoothScoOn()}
7531 * <li> {@link #isSpeakerphoneOn()}
7532 * </ul>
7533 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01007534 * currently selected for communication use cases. Can be null on platforms
7535 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007536 * is used.
7537 */
7538 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01007539 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007540 try {
7541 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01007542 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7543 } catch (RemoteException e) {
7544 throw e.rethrowFromSystemServer();
7545 }
7546 }
7547
7548 /**
7549 * Returns a list of audio devices that can be selected for communication use cases via
7550 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7551 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7552 */
7553 @NonNull
7554 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7555 try {
7556 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7557 int[] portIds = getService().getAvailableCommunicationDeviceIds();
7558 for (int portId : portIds) {
7559 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7560 if (device == null) {
7561 continue;
7562 }
7563 devices.add(device);
7564 }
7565 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007566 } catch (RemoteException e) {
7567 throw e.rethrowFromSystemServer();
7568 }
7569 }
7570
7571 /**
7572 * @hide
7573 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7574 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7575 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7576 * The method will return null if no device of the provided type is connected.
7577 * If more than one device of the provided type is connected, an object corresponding to the
7578 * first device encountered in the enumeration list will be returned.
7579 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01007580 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007581 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7582 * @throws IllegalArgumentException If an invalid device type is specified.
7583 */
7584 @TestApi
7585 @Nullable
7586 public static AudioDeviceInfo getDeviceInfoFromType(
7587 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01007588 return getDeviceInfoFromTypeAndAddress(deviceType, null);
7589 }
7590
Eric Laurent78eef3a2021-11-09 16:10:42 +01007591 /**
Eric Laurent7412f572021-02-11 15:10:31 +01007592 * @hide
7593 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7594 * address provided.
7595 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7596 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7597 * If a null address is provided, the matching will happen on the type only.
7598 * The method will return null if no device of the provided type and address is connected.
7599 * If more than one device of the provided type is connected, an object corresponding to the
7600 * first device encountered in the enumeration list will be returned.
7601 * @param type The device device for which an <code>AudioDeviceInfo</code>
7602 * object is queried.
7603 * @param address The device address for which an <code>AudioDeviceInfo</code>
7604 * object is queried or null if requesting match on type only.
7605 * @return An AudioDeviceInfo object or null if no matching device is connected.
7606 * @throws IllegalArgumentException If an invalid device type is specified.
7607 */
7608 @Nullable
7609 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7610 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007611 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01007612 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007613 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01007614 if (device.getType() == type) {
7615 deviceForType = device;
7616 if (address == null || address.equals(device.getAddress())) {
7617 return device;
7618 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007619 }
7620 }
Eric Laurent7412f572021-02-11 15:10:31 +01007621 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007622 }
7623
7624 /**
7625 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007626 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007627 */
7628 public interface OnCommunicationDeviceChangedListener {
7629 /**
7630 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007631 * @param device the audio device requested for communication use cases.
7632 * Can be null on platforms not supporting
7633 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007634 */
7635 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7636 }
7637
7638 /**
7639 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007640 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007641 * @param executor
7642 * @param listener
7643 */
7644 public void addOnCommunicationDeviceChangedListener(
7645 @NonNull @CallbackExecutor Executor executor,
7646 @NonNull OnCommunicationDeviceChangedListener listener) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007647 synchronized (mCommDevListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007648 final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
7649 CommunicationDeviceDispatcherStub> res =
7650 CallbackUtil.addListener("addOnCommunicationDeviceChangedListener",
7651 executor, listener, mCommDevListeners, mCommDevDispatcherStub,
7652 () -> new CommunicationDeviceDispatcherStub(),
7653 stub -> stub.register(true));
7654 mCommDevListeners = res.first;
7655 mCommDevDispatcherStub = res.second;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007656 }
7657 }
7658
7659 /**
7660 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007661 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007662 * @param listener
7663 */
7664 public void removeOnCommunicationDeviceChangedListener(
7665 @NonNull OnCommunicationDeviceChangedListener listener) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007666 synchronized (mCommDevListenerLock) {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007667 final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
7668 CommunicationDeviceDispatcherStub> res =
7669 CallbackUtil.removeListener("removeOnCommunicationDeviceChangedListener",
7670 listener, mCommDevListeners, mCommDevDispatcherStub,
7671 stub -> stub.register(false));
7672 mCommDevListeners = res.first;
7673 mCommDevDispatcherStub = res.second;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007674 }
7675 }
7676
7677 private final Object mCommDevListenerLock = new Object();
7678 /**
7679 * List of listeners for preferred device for strategy and their associated Executor.
7680 * List is lazy-initialized on first registration
7681 */
7682 @GuardedBy("mCommDevListenerLock")
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007683 private @Nullable
7684 ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>> mCommDevListeners;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007685
7686 @GuardedBy("mCommDevListenerLock")
7687 private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
7688
7689 private final class CommunicationDeviceDispatcherStub
7690 extends ICommunicationDeviceDispatcher.Stub {
7691
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007692 public void register(boolean register) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007693 try {
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007694 if (register) {
7695 getService().registerCommunicationDeviceDispatcher(this);
7696 } else {
7697 getService().unregisterCommunicationDeviceDispatcher(this);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007698 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007699 } catch (RemoteException e) {
7700 e.rethrowFromSystemServer();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007701 }
7702 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007703
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08007704 @Override
7705 @SuppressLint("GuardedBy") // lock applied inside callListeners method
7706 public void dispatchCommunicationDeviceChanged(int portId) {
7707 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7708 CallbackUtil.callListeners(mCommDevListeners, mCommDevListenerLock,
7709 (listener) -> listener.onCommunicationDeviceChanged(device));
Eric Laurentb36d4a12020-10-09 09:52:49 -07007710 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007711 }
7712
Eric Laurent78eef3a2021-11-09 16:10:42 +01007713
7714 /**
7715 * @hide
7716 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
7717 * PSTN call.
7718 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
7719 * an AudioTrack for call uplink audio injection and
7720 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
7721 * an AudioRecord for call downlink audio extraction.
7722 * @return true if PSTN call audio is accessible, false otherwise.
7723 */
7724 @TestApi
7725 @SystemApi
7726 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
7727 public boolean isPstnCallAudioInterceptable() {
7728 final IAudioService service = getService();
7729 try {
7730 return service.isPstnCallAudioInterceptable();
7731 } catch (RemoteException e) {
7732 throw e.rethrowFromSystemServer();
7733 }
7734 }
7735
7736 /** @hide */
7737 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
7738 CALL_REDIRECT_NONE,
7739 CALL_REDIRECT_PSTN,
7740 CALL_REDIRECT_VOIP }
7741 )
7742 @Retention(RetentionPolicy.SOURCE)
7743 public @interface CallRedirectionMode {}
7744
7745 /**
7746 * Not used for call redirection
7747 * @hide
7748 */
7749 public static final int CALL_REDIRECT_NONE = 0;
7750 /**
7751 * Used to redirect PSTN call
7752 * @hide
7753 */
7754 public static final int CALL_REDIRECT_PSTN = 1;
7755 /**
7756 * Used to redirect VoIP call
7757 * @hide
7758 */
7759 public static final int CALL_REDIRECT_VOIP = 2;
7760
7761
7762 private @CallRedirectionMode int getCallRedirectMode() {
7763 int mode = getMode();
7764 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
7765 || mode == MODE_CALL_REDIRECT) {
7766 return CALL_REDIRECT_PSTN;
7767 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
7768 return CALL_REDIRECT_VOIP;
7769 }
7770 return CALL_REDIRECT_NONE;
7771 }
7772
7773 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
7774 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
7775 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
7776 throw new UnsupportedOperationException(" Unsupported encoding ");
7777 }
7778 if (format.getSampleRate() < 8000
7779 || format.getSampleRate() > 48000) {
7780 throw new UnsupportedOperationException(" Unsupported sample rate ");
7781 }
7782 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
7783 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
7784 throw new UnsupportedOperationException(" Unsupported output channel mask ");
7785 }
7786 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
7787 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
7788 throw new UnsupportedOperationException(" Unsupported input channel mask ");
7789 }
7790 }
7791
7792 class CallIRedirectionClientInfo {
7793 public WeakReference trackOrRecord;
7794 public int redirectMode;
7795 }
7796
7797 private Object mCallRedirectionLock = new Object();
7798 @GuardedBy("mCallRedirectionLock")
7799 private CallInjectionModeChangedListener mCallRedirectionModeListener;
7800 @GuardedBy("mCallRedirectionLock")
7801 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
7802
7803 /**
7804 * @hide
7805 * Returns an AudioTrack that can be used to inject audio to an active call uplink.
7806 * This can be used for functions like call screening or call audio redirection and is reserved
7807 * to system apps with privileged permission.
7808 * @param format the desired audio format for audio playback.
7809 * p>Formats accepted are:
7810 * <ul>
7811 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
7812 * <li><em>Channel mask</em> - Mono or Stereo </li>
7813 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
7814 * </ul>
7815 *
7816 * @return The AudioTrack used for audio injection
7817 * @throws NullPointerException if AudioFormat argument is null.
7818 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
7819 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
7820 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
7821 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
7822 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
7823 * or MODE_COMMUNICATION_REDIRECT.
7824 */
7825 @TestApi
7826 @SystemApi
7827 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
7828 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
7829 Objects.requireNonNull(format);
7830 checkCallRedirectionFormat(format, true /* isOutput */);
7831
7832 AudioTrack track = null;
7833 int redirectMode = getCallRedirectMode();
7834 if (redirectMode == CALL_REDIRECT_NONE) {
7835 throw new IllegalStateException(
7836 " not available in mode " + AudioSystem.modeToString(getMode()));
7837 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
7838 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
7839 }
7840
7841 track = new AudioTrack.Builder()
7842 .setAudioAttributes(new AudioAttributes.Builder()
7843 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
7844 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
7845 .build())
7846 .setAudioFormat(format)
7847 .setCallRedirectionMode(redirectMode)
7848 .build();
7849
7850 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
7851 synchronized (mCallRedirectionLock) {
7852 if (mCallRedirectionModeListener == null) {
7853 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
7854 try {
7855 addOnModeChangedListener(
7856 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
7857 } catch (Exception e) {
7858 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
7859 mCallRedirectionModeListener = null;
7860 throw new UnsupportedOperationException(" Cannot register mode listener ");
7861 }
7862 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
7863 }
7864 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
7865 info.redirectMode = redirectMode;
7866 info.trackOrRecord = new WeakReference<AudioTrack>(track);
7867 mCallIRedirectionClients.add(info);
7868 }
7869 } else {
7870 throw new UnsupportedOperationException(" Cannot create the AudioTrack");
7871 }
7872 return track;
7873 }
7874
7875 /**
7876 * @hide
7877 * Returns an AudioRecord that can be used to extract audio from an active call downlink.
7878 * This can be used for functions like call screening or call audio redirection and is reserved
7879 * to system apps with privileged permission.
7880 * @param format the desired audio format for audio capture.
7881 *<p>Formats accepted are:
7882 * <ul>
7883 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
7884 * <li><em>Channel mask</em> - Mono or Stereo </li>
7885 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
7886 * </ul>
7887 *
7888 * @return The AudioRecord used for audio extraction
7889 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
7890 * @throws IllegalArgumentException if an invalid AudioFormat is specified.
7891 * @throws NullPointerException if AudioFormat argument is null.
7892 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing .
7893 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
7894 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
7895 * or MODE_COMMUNICATION_REDIRECT.
7896 */
7897 @TestApi
7898 @SystemApi
7899 @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)
7900 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
7901 Objects.requireNonNull(format);
7902 checkCallRedirectionFormat(format, false /* isOutput */);
7903
7904 AudioRecord record = null;
7905 int redirectMode = getCallRedirectMode();
7906 if (redirectMode == CALL_REDIRECT_NONE) {
7907 throw new IllegalStateException(
7908 " not available in mode " + AudioSystem.modeToString(getMode()));
7909 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
7910 throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
7911 }
7912
7913 record = new AudioRecord.Builder()
7914 .setAudioAttributes(new AudioAttributes.Builder()
7915 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
7916 .build())
7917 .setAudioFormat(format)
7918 .setCallRedirectionMode(redirectMode)
7919 .build();
7920
7921 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
7922 synchronized (mCallRedirectionLock) {
7923 if (mCallRedirectionModeListener == null) {
7924 mCallRedirectionModeListener = new CallInjectionModeChangedListener();
7925 try {
7926 addOnModeChangedListener(
7927 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
7928 } catch (Exception e) {
7929 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
7930 mCallRedirectionModeListener = null;
7931 throw new UnsupportedOperationException(" Cannot register mode listener ");
7932 }
7933 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
7934 }
7935 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
7936 info.redirectMode = redirectMode;
7937 info.trackOrRecord = new WeakReference<AudioRecord>(record);
7938 mCallIRedirectionClients.add(info);
7939 }
7940 } else {
7941 throw new UnsupportedOperationException(" Cannot create the AudioRecord");
7942 }
7943 return record;
7944 }
7945
7946 class CallInjectionModeChangedListener implements OnModeChangedListener {
7947 @Override
7948 public void onModeChanged(@AudioMode int mode) {
7949 synchronized (mCallRedirectionLock) {
7950 final ArrayList<CallIRedirectionClientInfo> clientInfos =
7951 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
7952 for (CallIRedirectionClientInfo info : clientInfos) {
7953 Object trackOrRecord = info.trackOrRecord.get();
7954 if (trackOrRecord != null) {
7955 if ((info.redirectMode == CALL_REDIRECT_PSTN
7956 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
7957 && mode != MODE_CALL_REDIRECT)
7958 || (info.redirectMode == CALL_REDIRECT_VOIP
7959 && mode != MODE_IN_COMMUNICATION
7960 && mode != MODE_COMMUNICATION_REDIRECT)) {
7961 if (trackOrRecord instanceof AudioTrack) {
7962 AudioTrack track = (AudioTrack) trackOrRecord;
7963 track.release();
7964 } else {
7965 AudioRecord record = (AudioRecord) trackOrRecord;
7966 record.release();
7967 }
7968 mCallIRedirectionClients.remove(info);
7969 }
7970 }
7971 }
7972 if (mCallIRedirectionClients.isEmpty()) {
7973 try {
7974 if (mCallRedirectionModeListener != null) {
7975 removeOnModeChangedListener(mCallRedirectionModeListener);
7976 }
7977 } catch (Exception e) {
7978 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
7979 } finally {
7980 mCallRedirectionModeListener = null;
7981 mCallIRedirectionClients = null;
7982 }
7983 }
7984 }
7985 }
7986 }
7987
Paul McLeane3383cc2015-05-08 11:41:20 -07007988 //---------------------------------------------------------
Jean-Michel Trivi933bf142021-11-19 16:18:52 -08007989 // audio device connection-dependent muting
7990 /**
7991 * @hide
7992 * Mute a set of playback use cases until a given audio device is connected.
7993 * Automatically unmute upon connection of the device, or after the given timeout, whichever
7994 * happens first.
7995 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
7996 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the
7997 * device connects
7998 * @param device the audio device expected to connect within the timeout duration
7999 * @param timeout the maximum amount of time to wait for the device connection
8000 * @param timeUnit the unit for the timeout
8001 * @throws IllegalStateException when trying to issue the command while another is already in
8002 * progress and hasn't been cancelled by
8003 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
8004 * {@link #getMutingExpectedDevice()} to check if a muting command is active.
8005 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8006 */
8007 @SystemApi
8008 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8009 public void muteAwaitConnection(@NonNull int[] usagesToMute,
8010 @NonNull AudioDeviceAttributes device,
8011 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
8012 if (timeout <= 0) {
8013 throw new IllegalArgumentException("Timeout must be greater than 0");
8014 }
8015 Objects.requireNonNull(usagesToMute);
8016 if (usagesToMute.length == 0) {
8017 throw new IllegalArgumentException("Array of usages to mute cannot be empty");
8018 }
8019 Objects.requireNonNull(device);
8020 Objects.requireNonNull(timeUnit);
8021 try {
8022 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
8023 } catch (RemoteException e) {
8024 throw e.rethrowFromSystemServer();
8025 }
8026 }
8027
8028 /**
8029 * @hide
8030 * Query which audio device, if any, is causing some playback use cases to be muted until it
8031 * connects.
8032 * @return the audio device used in
8033 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
8034 * if there is no active muting command (either because the muting command was not issued
8035 * or because it timed out)
8036 */
8037 @SystemApi
8038 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8039 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
8040 try {
8041 return getService().getMutingExpectedDevice();
8042 } catch (RemoteException e) {
8043 throw e.rethrowFromSystemServer();
8044 }
8045 }
8046
8047 /**
8048 * @hide
8049 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8050 * command.
8051 * @param device the device whose connection was expected when the {@code muteAwaitConnection}
8052 * command was issued.
8053 * @throws IllegalStateException when trying to issue the command for a device whose connection
8054 * is not anticipated by a previous call to
8055 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
8056 */
8057 @SystemApi
8058 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8059 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
8060 throws IllegalStateException {
8061 Objects.requireNonNull(device);
8062 try {
8063 getService().cancelMuteAwaitConnection(device);
8064 } catch (RemoteException e) {
8065 throw e.rethrowFromSystemServer();
8066 }
8067 }
8068
8069 /**
8070 * @hide
8071 * A callback class to receive events about the muting and unmuting of playback use cases
8072 * conditional on the upcoming connection of an audio device.
8073 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
8074 */
8075 @SystemApi
8076 public abstract static class MuteAwaitConnectionCallback {
8077
8078 /**
8079 * An event where the expected audio device connected
8080 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8081 */
8082 public static final int EVENT_CONNECTION = 1;
8083 /**
8084 * An event where the expected audio device failed connect before the timeout happened
8085 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8086 */
8087 public static final int EVENT_TIMEOUT = 2;
8088 /**
8089 * An event where the {@code muteAwaitConnection()} command
8090 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
8091 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
8092 */
8093 public static final int EVENT_CANCEL = 3;
8094
8095 /** @hide */
8096 @IntDef(flag = false, prefix = "EVENT_", value = {
8097 EVENT_CONNECTION,
8098 EVENT_TIMEOUT,
8099 EVENT_CANCEL }
8100 )
8101 @Retention(RetentionPolicy.SOURCE)
8102 public @interface UnmuteEvent {}
8103
8104 /**
8105 * Called when a number of playback use cases are muted in response to a call to
8106 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
8107 * @param device the audio device whose connection is expected. Playback use cases are
8108 * unmuted when that device connects
8109 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
8110 * playback use cases.
8111 */
8112 public void onMutedUntilConnection(
8113 @NonNull AudioDeviceAttributes device,
8114 @NonNull int[] mutedUsages) {}
8115
8116 /**
8117 * Called when an event occurred that caused playback uses cases to be unmuted
8118 * @param unmuteEvent the nature of the event
8119 * @param device the device that was expected to connect
8120 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
8121 * the event occurred
8122 */
8123 public void onUnmutedEvent(
8124 @UnmuteEvent int unmuteEvent,
8125 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
8126 }
8127
8128
8129 /**
8130 * @hide
8131 * Register a callback to receive updates on the playback muting conditional on a specific
8132 * audio device connection.
8133 * @param executor the {@link Executor} handling the callback
8134 * @param callback the callback to register
8135 */
8136 @SystemApi
8137 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8138 public void registerMuteAwaitConnectionCallback(
8139 @NonNull @CallbackExecutor Executor executor,
8140 @NonNull MuteAwaitConnectionCallback callback) {
8141 synchronized (mMuteAwaitConnectionListenerLock) {
8142 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8143 MuteAwaitConnectionDispatcherStub> res =
8144 CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
8145 executor, callback, mMuteAwaitConnectionListeners,
8146 mMuteAwaitConnDispatcherStub,
8147 () -> new MuteAwaitConnectionDispatcherStub(),
8148 stub -> stub.register(true));
8149 mMuteAwaitConnectionListeners = res.first;
8150 mMuteAwaitConnDispatcherStub = res.second;
8151 }
8152 }
8153
8154 /**
8155 * @hide
8156 * Unregister a previously registered callback for playback muting conditional on device
8157 * connection.
8158 * @param callback the callback to unregister
8159 */
8160 @SystemApi
8161 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
8162 public void unregisterMuteAwaitConnectionCallback(
8163 @NonNull MuteAwaitConnectionCallback callback) {
8164 synchronized (mMuteAwaitConnectionListenerLock) {
8165 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
8166 MuteAwaitConnectionDispatcherStub> res =
8167 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
8168 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
8169 stub -> stub.register(false));
8170 mMuteAwaitConnectionListeners = res.first;
8171 mMuteAwaitConnDispatcherStub = res.second;
8172 }
8173 }
8174
8175 private final Object mMuteAwaitConnectionListenerLock = new Object();
8176
8177 @GuardedBy("mMuteAwaitConnectionListenerLock")
8178 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
8179 mMuteAwaitConnectionListeners;
8180
8181 @GuardedBy("mMuteAwaitConnectionListenerLock")
8182 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
8183
8184 private final class MuteAwaitConnectionDispatcherStub
8185 extends IMuteAwaitConnectionCallback.Stub {
8186 public void register(boolean register) {
8187 try {
8188 getService().registerMuteAwaitConnectionDispatcher(this, register);
8189 } catch (RemoteException e) {
8190 throw e.rethrowFromSystemServer();
8191 }
8192 }
8193
8194 @Override
8195 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8196 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
8197 int[] mutedUsages) {
8198 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8199 mMuteAwaitConnectionListenerLock,
8200 (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
8201 }
8202
8203 @Override
8204 @SuppressLint("GuardedBy") // lock applied inside callListeners method
8205 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
8206 int[] mutedUsages) {
8207 CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
8208 mMuteAwaitConnectionListenerLock,
8209 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
8210 }
8211 }
8212
8213 //---------------------------------------------------------
Paul McLeane3383cc2015-05-08 11:41:20 -07008214 // Inner classes
8215 //--------------------
8216 /**
8217 * Helper class to handle the forwarding of native events to the appropriate listener
8218 * (potentially) handled in a different thread.
8219 */
8220 private class NativeEventHandlerDelegate {
8221 private final Handler mHandler;
8222
Paul McLean03346882015-05-12 15:36:56 -07008223 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07008224 Handler handler) {
8225 // find the looper for our new event handler
8226 Looper looper;
8227 if (handler != null) {
8228 looper = handler.getLooper();
8229 } else {
8230 // no given handler, use the looper the addListener call was called in
8231 looper = Looper.getMainLooper();
8232 }
8233
8234 // construct the event handler with this looper
8235 if (looper != null) {
8236 // implement the event handler delegate
8237 mHandler = new Handler(looper) {
8238 @Override
8239 public void handleMessage(Message msg) {
8240 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07008241 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07008242 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07008243 if (callback != null) {
8244 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07008245 }
8246 break;
Paul McLean03346882015-05-12 15:36:56 -07008247
8248 case MSG_DEVICES_DEVICES_REMOVED:
8249 if (callback != null) {
8250 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
8251 }
8252 break;
8253
Paul McLeane3383cc2015-05-08 11:41:20 -07008254 default:
8255 Log.e(TAG, "Unknown native event type: " + msg.what);
8256 break;
8257 }
8258 }
8259 };
8260 } else {
8261 mHandler = null;
8262 }
8263 }
8264
8265 Handler getHandler() {
8266 return mHandler;
8267 }
8268 }
Jean-Michel Trivi91f0baa2021-11-11 16:31:32 -08008269}