blob: c757b38d3887c0e5b4c9e39769950f7eb5ebc62f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
Jeff Sharkey098d5802012-04-26 17:30:34 -070019import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
Amith Yamasanic696a532011-10-28 17:02:37 -070020import static android.media.AudioManager.RINGER_MODE_NORMAL;
21import static android.media.AudioManager.RINGER_MODE_SILENT;
22import static android.media.AudioManager.RINGER_MODE_VIBRATE;
23
Glenn Kastenfd116ad2013-07-12 17:10:39 -070024import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.app.ActivityManagerNative;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070026import android.app.AppOpsManager;
Amith Yamasani6243edd2011-12-05 19:58:48 -080027import android.app.KeyguardManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070028import android.app.PendingIntent;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070029import android.bluetooth.BluetoothA2dp;
30import android.bluetooth.BluetoothAdapter;
31import android.bluetooth.BluetoothClass;
32import android.bluetooth.BluetoothDevice;
33import android.bluetooth.BluetoothHeadset;
34import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070035import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070036import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.ContentResolver;
38import android.content.Context;
39import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070040import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.content.pm.PackageManager;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070042import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070043import android.content.res.Resources;
44import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070045import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090046import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070047import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090048import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070049import android.hardware.usb.UsbManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.media.MediaPlayer.OnCompletionListener;
51import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070052import android.media.audiopolicy.AudioPolicyConfig;
RoboErik8a2cfc32014-05-16 11:19:38 -070053import android.media.session.MediaSessionLegacyHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070055import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Environment;
57import android.os.Handler;
58import android.os.IBinder;
59import android.os.Looper;
60import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070061import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070062import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.RemoteException;
64import android.os.ServiceManager;
John Spurlock33f4e042014-07-11 13:10:58 -040065import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070066import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070067import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070068import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.provider.Settings;
70import android.provider.Settings.System;
Santos Cordon9eb45932014-06-27 12:28:43 -070071import android.telecomm.TelecommManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070072import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040074import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070075import android.util.Slog;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070076import android.view.KeyEvent;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070077import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070078import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
80import com.android.internal.telephony.ITelephony;
Eric Laurente78fced2013-03-15 16:03:47 -070081import com.android.internal.util.XmlUtils;
82
83import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080085import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080087import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -070088import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import java.util.ArrayList;
Eric Laurent3172d5e2012-05-09 11:38:16 -070090import java.util.concurrent.ConcurrentHashMap;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +090091import java.util.Arrays;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070092import java.util.HashMap;
93import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070094import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070095import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070096import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -070097import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070098import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
100/**
101 * The implementation of the volume manager service.
102 * <p>
103 * This implementation focuses on delivering a responsive UI. Most methods are
104 * asynchronous to external calls. For example, the task of setting a volume
105 * will update our internal state, but in a separate thread will set the system
106 * volume and later persist to the database. Similarly, setting the ringer mode
107 * will update the state and broadcast a change and in a separate thread later
108 * persist the ringer mode.
109 *
110 * @hide
111 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700112public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
114 private static final String TAG = "AudioService";
115
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700116 /** Debug audio mode */
117 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700118 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400119 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700120
RoboErik430fc482014-06-12 15:49:20 -0700121 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400122 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700123
John Spurlock86005342014-05-23 11:58:00 -0400124 /** Allow volume changes to set ringer mode to silent? */
125 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
126
John Spurlocka11b4af2014-06-01 11:52:23 -0400127 /** In silent mode, are volume adjustments (raises) prevented? */
128 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700131 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
John Spurlock3346a802014-05-20 16:25:37 -0400133 /**
134 * The delay before playing a sound. This small period exists so the user
135 * can press another key (non-volume keys, too) to have it NOT be audible.
136 * <p>
137 * PhoneWindow will implement this part.
138 */
139 public static final int PLAY_SOUND_DELAY = 300;
140
John Spurlocka11b4af2014-06-01 11:52:23 -0400141 /**
142 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
143 */
144 private static final int FLAG_ADJUST_VOLUME = 1;
145
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700146 private final Context mContext;
147 private final ContentResolver mContentResolver;
148 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700149
150 // the platform has no specific capabilities
151 private static final int PLATFORM_DEFAULT = 0;
152 // the platform is voice call capable (a phone)
153 private static final int PLATFORM_VOICE = 1;
154 // the platform is a television or a set-top box
155 private static final int PLATFORM_TELEVISION = 2;
156 // the platform type affects volume and silent mode behavior
157 private final int mPlatformType;
158
159 private boolean isPlatformVoice() {
160 return mPlatformType == PLATFORM_VOICE;
161 }
162
163 private boolean isPlatformTelevision() {
164 return mPlatformType == PLATFORM_TELEVISION;
165 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800166
John Spurlock3346a802014-05-20 16:25:37 -0400167 /** The controller for the volume UI. */
168 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
170 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 /** If the msg is already queued, replace it with this one. */
172 private static final int SENDMSG_REPLACE = 0;
173 /** If the msg is already queued, ignore this one and leave the old. */
174 private static final int SENDMSG_NOOP = 1;
175 /** If the msg is already queued, queue this one and leave the old. */
176 private static final int SENDMSG_QUEUE = 2;
177
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700178 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800179 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500181 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700183 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700184 private static final int MSG_PLAY_SOUND_EFFECT = 5;
185 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
186 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
187 private static final int MSG_SET_FORCE_USE = 8;
188 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
189 private static final int MSG_SET_ALL_VOLUMES = 10;
190 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
191 private static final int MSG_REPORT_NEW_ROUTES = 12;
192 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
193 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
194 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
195 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
196 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
197 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
198 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
199 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700200 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400201 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700202 // start of messages handled under wakelock
203 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700204 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700205 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700206 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
207 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700208 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800209
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700210 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700211 // Timeout for connection to bluetooth headset service
212 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 /** @see AudioSystemThread */
215 private AudioSystemThread mAudioSystemThread;
216 /** @see AudioHandler */
217 private AudioHandler mAudioHandler;
218 /** @see VolumeStreamState */
219 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700220 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700221
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700222 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800223 // protects mRingerMode
224 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800227 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229
Mike Lockwood47676902011-11-08 10:31:21 -0800230 // Internally master volume is a float in the 0.0 - 1.0 range,
231 // but to support integer based AudioManager API we translate it to 0 - 100
232 private static final int MAX_MASTER_VOLUME = 100;
233
Lei Zhang6c798972012-03-02 11:40:12 -0800234 // Maximum volume adjust steps allowed in a single batch call.
235 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 /* Sound effect file names */
238 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700239 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
242 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
243 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700244 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
Jared Suttles59820132009-08-13 21:50:52 -0500246 /** @hide Maximum volume index values for audio streams */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700247 private static final int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700248 5, // STREAM_VOICE_CALL
249 7, // STREAM_SYSTEM
250 7, // STREAM_RING
251 15, // STREAM_MUSIC
252 7, // STREAM_ALARM
253 7, // STREAM_NOTIFICATION
254 15, // STREAM_BLUETOOTH_SCO
255 7, // STREAM_SYSTEM_ENFORCED
256 15, // STREAM_DTMF
257 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500258 };
Eric Laurent6d517662012-04-23 18:42:39 -0700259 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700260 * of another stream: This avoids multiplying the volume settings for hidden
261 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700262 * NOTE: do not create loops in aliases!
263 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700264 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700265 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
266 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
267 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
268 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700269 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
270 AudioSystem.STREAM_RING, // STREAM_SYSTEM
271 AudioSystem.STREAM_RING, // STREAM_RING
272 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
273 AudioSystem.STREAM_ALARM, // STREAM_ALARM
274 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
275 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
276 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
277 AudioSystem.STREAM_RING, // STREAM_DTMF
278 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700279 };
Eric Laurent212532b2014-07-21 15:43:18 -0700280 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
281 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
282 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
283 AudioSystem.STREAM_MUSIC, // STREAM_RING
284 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
285 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
286 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
287 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
288 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
289 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
290 AudioSystem.STREAM_MUSIC // STREAM_TTS
291 };
292 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700293 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400294 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700295 AudioSystem.STREAM_RING, // STREAM_RING
296 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
297 AudioSystem.STREAM_ALARM, // STREAM_ALARM
298 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
299 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400300 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
301 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700302 AudioSystem.STREAM_MUSIC // STREAM_TTS
303 };
304 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700305
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700306 /**
307 * Map AudioSystem.STREAM_* constants to app ops. This should be used
308 * after mapping through mStreamVolumeAlias.
309 */
310 private static final int[] STEAM_VOLUME_OPS = new int[] {
311 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
312 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
313 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
314 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
315 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
316 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
317 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
318 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
319 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
320 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
321 };
322
Eric Laurent83a017b2013-03-19 18:15:31 -0700323 private final boolean mUseFixedVolume;
324
Eric Laurentbffc3d12012-05-07 17:43:49 -0700325 // stream names used by dumpStreamStates()
John Spurlock1af30c72014-03-10 08:33:35 -0400326 private static final String[] STREAM_NAMES = new String[] {
Eric Laurentbffc3d12012-05-07 17:43:49 -0700327 "STREAM_VOICE_CALL",
328 "STREAM_SYSTEM",
329 "STREAM_RING",
330 "STREAM_MUSIC",
331 "STREAM_ALARM",
332 "STREAM_NOTIFICATION",
333 "STREAM_BLUETOOTH_SCO",
334 "STREAM_SYSTEM_ENFORCED",
335 "STREAM_DTMF",
336 "STREAM_TTS"
337 };
338
Glenn Kasten30c918c2011-11-10 17:56:41 -0800339 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 public void onError(int error) {
341 switch (error) {
342 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700343 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
344 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 break;
346 default:
347 break;
348 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 };
351
352 /**
353 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
354 * {@link AudioManager#RINGER_MODE_SILENT}, or
355 * {@link AudioManager#RINGER_MODE_VIBRATE}.
356 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800357 // protected by mSettingsLock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 private int mRingerMode;
359
Eric Laurent9bcf4012009-06-12 06:09:28 -0700360 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700361 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700362
Eric Laurent5b4e6542010-03-19 20:02:21 -0700363 // Streams currently muted by ringer mode
364 private int mRingerModeMutedStreams;
365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 /** @see System#MUTE_STREAMS_AFFECTED */
367 private int mMuteAffectedStreams;
368
369 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700370 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
371 * mVibrateSetting is just maintained during deprecation period but vibration policy is
372 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 */
374 private int mVibrateSetting;
375
Eric Laurentbffc3d12012-05-07 17:43:49 -0700376 // Is there a vibrator
377 private final boolean mHasVibrator;
378
Eric Laurenta553c252009-07-17 12:17:14 -0700379 // Broadcast receiver for device connections intent broadcasts
380 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
381
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700382 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800383 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700384
385 // Forced device usage for communications
386 private int mForcedUseForComm;
387
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500388 // True if we have master volume support
389 private final boolean mUseMasterVolume;
390
Mike Lockwood97606472012-02-09 11:24:10 -0800391 private final int[] mMasterVolumeRamp;
392
Eric Laurent9272b4b2010-01-23 17:12:59 -0800393 // List of binder death handlers for setMode() client processes.
394 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800395 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800396
Eric Laurent3def1ee2010-03-17 23:26:26 -0700397 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800398 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700399
400 // BluetoothHeadset API to control SCO connection
401 private BluetoothHeadset mBluetoothHeadset;
402
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700403 // Bluetooth headset device
404 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700405
Eric Laurent62ef7672010-11-24 10:58:32 -0800406 // Indicate if SCO audio connection is currently active and if the initiator is
407 // audio service (internal) or bluetooth headset (external)
408 private int mScoAudioState;
409 // SCO audio state is not active
410 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700411 // SCO audio activation request waiting for headset service to connect
412 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700413 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700414 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
415 // SCO audio deactivation request waiting for headset service to connect
416 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
417
Eric Laurent62ef7672010-11-24 10:58:32 -0800418 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
419 // in call audio)
420 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700421 // Deactivation request for all SCO connections (initiated by audio mode change)
422 // waiting for headset service to connect
423 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
424
Eric Laurentc18c9132013-04-12 17:24:56 -0700425 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
426 // originated from an app targeting an API version before JB MR2 and raw audio after that.
427 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700428 // SCO audio mode is undefined
429 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700430 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
431 private static final int SCO_MODE_VIRTUAL_CALL = 0;
432 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
433 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700434 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
435 private static final int SCO_MODE_VR = 2;
436
437 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700438
Eric Laurentdc03c612011-04-01 10:59:41 -0700439 // Current connection state indicated by bluetooth headset
440 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800441
Eric Laurenta60e2122010-12-28 16:49:07 -0800442 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700443 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800444 // listener for SoundPool sample load completion indication
445 private SoundPoolCallback mSoundPoolCallBack;
446 // thread for SoundPool listener
447 private SoundPoolListenerThread mSoundPoolListenerThread;
448 // message looper for SoundPool listener
449 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700450 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700451 private static int sSoundEffectVolumeDb;
Eric Laurent9903e262012-09-21 18:10:32 -0700452 // getActiveStreamType() will return:
453 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
454 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
Eric Laurent25101b02011-02-02 09:33:30 -0800455 // stopped
Eric Laurent9903e262012-09-21 18:10:32 -0700456 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
Eric Laurent25101b02011-02-02 09:33:30 -0800457 // previous volume adjustment direction received by checkForRingerModeChange()
458 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800459 // Keyguard manager proxy
460 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700461 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
462 // is controlled by Vol keys.
463 private int mVolumeControlStream = -1;
464 private final Object mForceControlStreamLock = new Object();
465 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
466 // server process so in theory it is not necessary to monitor the client death.
467 // However it is good to be ready for future evolutions.
468 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700469 // Used to play ringtones outside system_server
470 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800471
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700472 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700473 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700474
Eric Laurent78472112012-05-21 08:57:21 -0700475 // Request to override default use of A2DP for media.
476 private boolean mBluetoothA2dpEnabled;
477 private final Object mBluetoothA2dpEnabledLock = new Object();
478
Dianne Hackborn632ca412012-06-14 19:34:10 -0700479 // Monitoring of audio routes. Protected by mCurAudioRoutes.
480 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
481 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
482 = new RemoteCallbackList<IAudioRoutesObserver>();
483
Eric Laurent4bbcc652012-09-24 14:26:30 -0700484 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700485 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700486 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700487 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
488 AudioSystem.DEVICE_OUT_HDMI_ARC |
489 AudioSystem.DEVICE_OUT_SPDIF |
490 AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700491
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700492 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700493 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700494 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700495
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700496 private boolean mDockAudioMediaEnabled = true;
497
Eric Laurent08ed1b92012-11-05 14:54:12 -0800498 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
499
Eric Laurentfde16d52012-12-03 14:42:39 -0800500 // Used when safe volume warning message display is requested by setStreamVolume(). In this
501 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
502 // and used later when/if disableSafeMediaVolume() is called.
503 private StreamVolumeCommand mPendingVolumeCommand;
504
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700505 private PowerManager.WakeLock mAudioEventWakeLock;
506
507 private final MediaFocusControl mMediaFocusControl;
508
John Du5a0cf7a2013-07-19 11:30:34 -0700509 // Reference to BluetoothA2dp to query for AbsoluteVolume.
510 private BluetoothA2dp mA2dp;
511 private final Object mA2dpAvrcpLock = new Object();
512 // If absolute volume is supported in AVRCP device
513 private boolean mAvrcpAbsVolSupported = false;
514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 ///////////////////////////////////////////////////////////////////////////
516 // Construction
517 ///////////////////////////////////////////////////////////////////////////
518
519 /** @hide */
520 public AudioService(Context context) {
521 mContext = context;
522 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700523 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700524
525 if (mContext.getResources().getBoolean(
526 com.android.internal.R.bool.config_voice_capable)) {
527 mPlatformType = PLATFORM_VOICE;
528 } else if (context.getPackageManager().hasSystemFeature(
529 PackageManager.FEATURE_TELEVISION)) {
530 mPlatformType = PLATFORM_TELEVISION;
531 } else {
532 mPlatformType = PLATFORM_DEFAULT;
533 }
Jared Suttles59820132009-08-13 21:50:52 -0500534
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700535 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700536 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700537
Eric Laurentbffc3d12012-05-07 17:43:49 -0700538 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
539 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
540
Jared Suttles59820132009-08-13 21:50:52 -0500541 // Intialized volume
542 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
543 "ro.config.vc_call_vol_steps",
544 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
545
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700546 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700547 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800548
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700549 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700552
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700553 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400554 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700555
Eric Laurentdfb881f2013-07-18 14:41:39 -0700556 AudioSystem.setErrorCallback(mAudioSystemCallback);
557
Eric Laurentdd45d012012-10-08 09:04:34 -0700558 boolean cameraSoundForced = mContext.getResources().getBoolean(
559 com.android.internal.R.bool.config_camera_sound_forced);
560 mCameraSoundForced = new Boolean(cameraSoundForced);
561 sendMsg(mAudioHandler,
562 MSG_SET_FORCE_USE,
563 SENDMSG_QUEUE,
564 AudioSystem.FOR_SYSTEM,
565 cameraSoundForced ?
566 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
567 null,
568 0);
569
Eric Laurent05274f32012-11-29 12:48:18 -0800570 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
571 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
572 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
573 // The default safe volume index read here will be replaced by the actual value when
574 // the mcc is read by onConfigureSafeVolume()
575 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
576 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
577
Eric Laurent83a017b2013-03-19 18:15:31 -0700578 mUseFixedVolume = mContext.getResources().getBoolean(
579 com.android.internal.R.bool.config_useFixedVolume);
580
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700581 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
582 // array initialized by updateStreamVolumeAlias()
583 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700585 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700586 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700587
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700588 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700589
590 // Call setRingerModeInt() to apply correct mute
591 // state on streams affected by ringer mode.
592 mRingerModeMutedStreams = 0;
593 setRingerModeInt(getRingerMode(), false);
594
Eric Laurenta553c252009-07-17 12:17:14 -0700595 // Register for device connection intent broadcasts.
596 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700597 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700598 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
599 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent59f48272012-04-05 19:42:21 -0700600 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
601 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700602 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
603 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700604 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700605 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700606
Eric Laurentd640bd32012-09-28 18:01:48 -0700607 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700608 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700609 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
610 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700611 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700612 // initialize orientation in AudioSystem
613 setOrientationForAudioSystem();
614 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700615 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
616 if (mMonitorRotation) {
617 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
618 .getDefaultDisplay().getRotation();
619 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
620 // initialize rotation in AudioSystem
621 setRotationForAudioSystem();
622 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700623
Eric Laurenta553c252009-07-17 12:17:14 -0700624 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500625
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500626 mUseMasterVolume = context.getResources().getBoolean(
627 com.android.internal.R.bool.config_useMasterVolume);
Mike Lockwood90631542012-01-06 11:20:37 -0500628 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800629
630 mMasterVolumeRamp = context.getResources().getIntArray(
631 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent78472112012-05-21 08:57:21 -0700632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 }
634
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700635 public void systemReady() {
636 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
637 0, 0, null, 0);
638 }
639
640 public void onSystemReady() {
641 mSystemReady = true;
642 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
643 0, 0, null, 0);
644
645 mKeyguardManager =
646 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
647 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
648 resetBluetoothSco();
649 getBluetoothHeadset();
650 //FIXME: this is to maintain compatibility with deprecated intent
651 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
652 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
653 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
654 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
655 sendStickyBroadcastToAll(newIntent);
656
657 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
658 if (adapter != null) {
659 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
660 BluetoothProfile.A2DP);
661 }
662
Eric Laurent212532b2014-07-21 15:43:18 -0700663 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900664 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700665 if (mHdmiManager != null) {
666 synchronized (mHdmiManager) {
667 mHdmiTvClient = mHdmiManager.getTvClient();
668 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
669 mHdmiCecSink = false;
670 }
671 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900672
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700673 sendMsg(mAudioHandler,
674 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
675 SENDMSG_REPLACE,
676 0,
677 0,
678 null,
679 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
680 }
681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 private void createAudioSystemThread() {
683 mAudioSystemThread = new AudioSystemThread();
684 mAudioSystemThread.start();
685 waitForAudioHandlerCreation();
686 }
687
688 /** Waits for the volume handler to be created by the other thread. */
689 private void waitForAudioHandlerCreation() {
690 synchronized(this) {
691 while (mAudioHandler == null) {
692 try {
693 // Wait for mAudioHandler to be set by the other thread
694 wait();
695 } catch (InterruptedException e) {
696 Log.e(TAG, "Interrupted while waiting on volume handler.");
697 }
698 }
699 }
700 }
701
Eric Laurent24482012012-05-10 09:41:17 -0700702 private void checkAllAliasStreamVolumes() {
703 int numStreamTypes = AudioSystem.getNumStreamTypes();
704 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
705 if (streamType != mStreamVolumeAlias[streamType]) {
706 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700707 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent24482012012-05-10 09:41:17 -0700708 }
709 // apply stream volume
Eric Laurent42b041e2013-03-29 11:36:03 -0700710 if (!mStreamStates[streamType].isMuted()) {
Eric Laurent24482012012-05-10 09:41:17 -0700711 mStreamStates[streamType].applyAllVolumes();
712 }
713 }
714 }
715
Eric Laurent212532b2014-07-21 15:43:18 -0700716 private void checkAllFixedVolumeDevices()
717 {
718 int numStreamTypes = AudioSystem.getNumStreamTypes();
719 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
720 mStreamStates[streamType].checkFixedVolumeDevices();
721 }
722 }
723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 int numStreamTypes = AudioSystem.getNumStreamTypes();
726 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
727
728 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700729 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731
Eric Laurent212532b2014-07-21 15:43:18 -0700732 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700733 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 }
735
Eric Laurentbffc3d12012-05-07 17:43:49 -0700736 private void dumpStreamStates(PrintWriter pw) {
737 pw.println("\nStream volumes (device: index)");
738 int numStreamTypes = AudioSystem.getNumStreamTypes();
739 for (int i = 0; i < numStreamTypes; i++) {
740 pw.println("- "+STREAM_NAMES[i]+":");
741 mStreamStates[i].dump(pw);
742 pw.println("");
743 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700744 pw.print("\n- mute affected streams = 0x");
745 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700746 }
747
John Spurlock1af30c72014-03-10 08:33:35 -0400748 /** @hide */
749 public static String streamToString(int stream) {
750 if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
751 if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
752 return "UNKNOWN_STREAM_" + stream;
753 }
Eric Laurent6d517662012-04-23 18:42:39 -0700754
755 private void updateStreamVolumeAlias(boolean updateVolumes) {
756 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700757
758 switch (mPlatformType) {
759 case PLATFORM_VOICE:
760 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700761 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700762 break;
763 case PLATFORM_TELEVISION:
764 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
765 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
766 break;
767 default:
768 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700769 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
770 }
Eric Laurent212532b2014-07-21 15:43:18 -0700771
772 if (isPlatformTelevision()) {
773 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700774 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700775 if (isInCommunication()) {
776 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
777 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
778 } else {
779 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
780 }
Eric Laurent6d517662012-04-23 18:42:39 -0700781 }
Eric Laurent212532b2014-07-21 15:43:18 -0700782
Eric Laurent6d517662012-04-23 18:42:39 -0700783 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
784 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700785 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700786 // apply stream mute states according to new value of mRingerModeAffectedStreams
787 setRingerModeInt(getRingerMode(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700788 sendMsg(mAudioHandler,
789 MSG_SET_ALL_VOLUMES,
790 SENDMSG_QUEUE,
791 0,
792 0,
793 mStreamStates[AudioSystem.STREAM_DTMF], 0);
794 }
795 }
796
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700797 private void readDockAudioSettings(ContentResolver cr)
798 {
799 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700800 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700801
802 if (mDockAudioMediaEnabled) {
803 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
804 } else {
805 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
806 }
807
808 sendMsg(mAudioHandler,
809 MSG_SET_FORCE_USE,
810 SENDMSG_QUEUE,
811 AudioSystem.FOR_DOCK,
812 mDockAudioMediaEnabled ?
813 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
814 null,
815 0);
816 }
817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 private void readPersistedSettings() {
819 final ContentResolver cr = mContentResolver;
820
Eric Laurentbffc3d12012-05-07 17:43:49 -0700821 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700822 Settings.Global.getInt(
823 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700824 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700825 // sanity check in case the settings are restored from a device with incompatible
826 // ringer modes
Glenn Kastenba195eb2011-12-13 09:30:40 -0800827 if (!AudioManager.isValidRingerMode(ringerMode)) {
828 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700829 }
830 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
831 ringerMode = AudioManager.RINGER_MODE_SILENT;
832 }
833 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700834 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800835 }
Eric Laurent212532b2014-07-21 15:43:18 -0700836 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700837 ringerMode = AudioManager.RINGER_MODE_NORMAL;
838 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800839 synchronized(mSettingsLock) {
840 mRingerMode = ringerMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841
Eric Laurentdd45d012012-10-08 09:04:34 -0700842 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
843 // are still needed while setVibrateSetting() and getVibrateSetting() are being
844 // deprecated.
845 mVibrateSetting = getValueForVibrateSetting(0,
846 AudioManager.VIBRATE_TYPE_NOTIFICATION,
847 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
848 : AudioManager.VIBRATE_SETTING_OFF);
849 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
850 AudioManager.VIBRATE_TYPE_RINGER,
851 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
852 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700854 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700855 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800856 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700857
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700858 mMuteAffectedStreams = System.getIntForUser(cr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 System.MUTE_STREAMS_AFFECTED,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700860 ((1 << AudioSystem.STREAM_MUSIC)|
861 (1 << AudioSystem.STREAM_RING)|
862 (1 << AudioSystem.STREAM_SYSTEM)),
863 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700865 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
866 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700867 if (mUseFixedVolume) {
868 masterMute = false;
869 AudioSystem.setMasterVolume(1.0f);
870 }
Justin Koh57978ed2012-04-03 17:37:58 -0700871 AudioSystem.setMasterMute(masterMute);
872 broadcastMasterMuteStatus(masterMute);
873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 // Each stream will read its own persisted settings
875
876 // Broadcast the sticky intent
Glenn Kastenba195eb2011-12-13 09:30:40 -0800877 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878
879 // Broadcast vibrate settings
880 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
881 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700882
John Spurlock33f4e042014-07-11 13:10:58 -0400883 // Load settings for the volume controller
884 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
886
Eric Laurenta553c252009-07-17 12:17:14 -0700887 private int rescaleIndex(int index, int srcStream, int dstStream) {
888 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890
891 ///////////////////////////////////////////////////////////////////////////
892 // IPC methods
893 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700895 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
896 String callingPackage) {
John Spurlockae641c92014-06-30 18:11:40 -0400897 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
898 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800899 int streamType;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700900 if (mVolumeControlStream != -1) {
901 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800902 } else {
903 streamType = getActiveStreamType(suggestedStreamType);
904 }
John Spurlock33f4e042014-07-11 13:10:58 -0400905 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906
RoboErik2811dd32014-08-12 09:48:13 -0700907 // Play sounds on STREAM_RING only.
908 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400909 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 flags &= ~AudioManager.FLAG_PLAY_SOUND;
911 }
912
John Spurlock33f4e042014-07-11 13:10:58 -0400913 // For notifications/ring, show the ui before making any adjustments
914 if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
915 direction = 0;
916 flags &= ~AudioManager.FLAG_PLAY_SOUND;
917 flags &= ~AudioManager.FLAG_VIBRATE;
918 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
919 }
920
RoboErik2811dd32014-08-12 09:48:13 -0700921 adjustStreamVolume(streamType, direction, flags, callingPackage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 }
923
924 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700925 public void adjustStreamVolume(int streamType, int direction, int flags,
926 String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700927 if (mUseFixedVolume) {
928 return;
929 }
John Spurlockae641c92014-06-30 18:11:40 -0400930 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
931 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 ensureValidDirection(direction);
934 ensureValidStreamType(streamType);
935
Eric Laurent96a33d12011-11-08 10:31:57 -0800936 // use stream type alias here so that streams with same alias have the same behavior,
937 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
938 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -0700939 int streamTypeAlias = mStreamVolumeAlias[streamType];
Eric Laurentb024c302011-10-14 17:19:27 -0700940 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800941
942 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -0800943
Eric Laurent42b041e2013-03-29 11:36:03 -0700944 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -0800946 int step;
Eric Laurent24482012012-05-10 09:41:17 -0700947
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700948 // skip a2dp absolute volume control request when the device
949 // is not an a2dp device
950 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
951 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
952 return;
953 }
954
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700955 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
956 callingPackage) != AppOpsManager.MODE_ALLOWED) {
957 return;
958 }
959
Eric Laurentfde16d52012-12-03 14:42:39 -0800960 // reset any pending volume command
961 synchronized (mSafeMediaVolumeState) {
962 mPendingVolumeCommand = null;
963 }
964
Eric Laurent3ef75492012-11-28 12:12:23 -0800965 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
966 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
967 ((device & mFixedVolumeDevices) != 0)) {
968 flags |= AudioManager.FLAG_FIXED_VOLUME;
969
970 // Always toggle between max safe volume and 0 for fixed volume devices where safe
971 // volume is enforced, and max and 0 for the others.
972 // This is simulated by stepping by the full allowed volume range
973 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
974 (device & mSafeMediaVolumeDevices) != 0) {
975 step = mSafeMediaVolumeIndex;
976 } else {
977 step = streamState.getMaxIndex();
978 }
979 if (aliasIndex != 0) {
980 aliasIndex = step;
981 }
982 } else {
983 // convert one UI step (+/-1) into a number of internal units on the stream alias
984 step = rescaleIndex(10, streamType, streamTypeAlias);
985 }
986
Eric Laurent42b041e2013-03-29 11:36:03 -0700987 // If either the client forces allowing ringer modes for this adjustment,
988 // or the stream type is one that is affected by ringer modes
989 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
990 (streamTypeAlias == getMasterStreamType())) {
991 int ringerMode = getRingerMode();
992 // do not vibrate if already in vibrate mode
993 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
994 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -0800995 }
Eric Laurent42b041e2013-03-29 11:36:03 -0700996 // Check if the ringer mode changes with this volume adjustment. If
997 // it does, it will handle adjusting the volume, so we won't below
John Spurlocka11b4af2014-06-01 11:52:23 -0400998 final int result = checkForRingerModeChange(aliasIndex, direction, step);
999 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1000 // If suppressing a volume adjustment in silent mode, display the UI hint
1001 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1002 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1003 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001004 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001005
Eric Laurent42b041e2013-03-29 11:36:03 -07001006 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001007
Eric Laurent42b041e2013-03-29 11:36:03 -07001008 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001009
John Du5a0cf7a2013-07-19 11:30:34 -07001010 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001011 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1012 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1013 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1014 synchronized (mA2dpAvrcpLock) {
1015 if (mA2dp != null && mAvrcpAbsVolSupported) {
1016 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1017 }
John Du5a0cf7a2013-07-19 11:30:34 -07001018 }
1019 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001020
Eric Laurent42b041e2013-03-29 11:36:03 -07001021 if ((direction == AudioManager.ADJUST_RAISE) &&
1022 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
1023 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001024 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurent42b041e2013-03-29 11:36:03 -07001025 } else if (streamState.adjustIndex(direction * step, device)) {
1026 // Post message to set system volume (it in turn will post a message
1027 // to persist). Do not change volume if stream is muted.
1028 sendMsg(mAudioHandler,
1029 MSG_SET_DEVICE_VOLUME,
1030 SENDMSG_QUEUE,
1031 device,
1032 0,
1033 streamState,
1034 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001035 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001036
1037 // Check if volume update should be send to Hdmi system audio.
1038 int newIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent212532b2014-07-21 15:43:18 -07001039 if (mHdmiManager != null) {
1040 synchronized (mHdmiManager) {
1041 if (mHdmiTvClient != null &&
1042 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1043 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1044 oldIndex != newIndex) {
1045 int maxIndex = getStreamMaxVolume(streamType);
1046 synchronized (mHdmiTvClient) {
1047 if (mHdmiSystemAudioSupported) {
1048 mHdmiTvClient.setSystemAudioVolume(
1049 (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
1050 }
1051 }
1052 }
1053 // mHdmiCecSink true => mHdmiPlaybackClient != null
1054 if (mHdmiCecSink &&
1055 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1056 oldIndex != newIndex) {
1057 synchronized (mHdmiPlaybackClient) {
1058 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
1059 KeyEvent.KEYCODE_VOLUME_UP;
1060 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1061 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1062 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001063 }
1064 }
1065 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001066 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001067 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001068 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 }
1070
Dianne Hackborn961cae92013-03-20 14:59:43 -07001071 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001072 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001073 if (mUseFixedVolume) {
1074 return;
1075 }
Lei Zhang6c798972012-03-02 11:40:12 -08001076 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001077 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1078 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001079 int numSteps = Math.abs(steps);
1080 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1081 for (int i = 0; i < numSteps; ++i) {
1082 delta = findVolumeDelta(direction, volume);
1083 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001084 }
RoboErik24b082f2012-02-24 14:21:16 -08001085
Lei Zhang6c798972012-03-02 11:40:12 -08001086 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001087 setMasterVolume(volume, flags, callingPackage);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001088 }
1089
Eric Laurentfde16d52012-12-03 14:42:39 -08001090 // StreamVolumeCommand contains the information needed to defer the process of
1091 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1092 class StreamVolumeCommand {
1093 public final int mStreamType;
1094 public final int mIndex;
1095 public final int mFlags;
1096 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001097
Eric Laurentfde16d52012-12-03 14:42:39 -08001098 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1099 mStreamType = streamType;
1100 mIndex = index;
1101 mFlags = flags;
1102 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001103 }
John Spurlock35134602014-07-24 18:10:48 -04001104
1105 @Override
1106 public String toString() {
1107 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1108 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1109 .append(mDevice).append('}').toString();
1110 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001111 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001112
Eric Laurentfde16d52012-12-03 14:42:39 -08001113 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001114 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001115 // setting volume on master stream type also controls silent mode
1116 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1117 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1118 int newRingerMode;
1119 if (index == 0) {
1120 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001121 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1122 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001123 } else {
1124 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1125 }
1126 setRingerMode(newRingerMode);
1127 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001128 }
1129
1130 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001131 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001132 if (mUseFixedVolume) {
1133 return;
1134 }
1135
Eric Laurentfde16d52012-12-03 14:42:39 -08001136 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001137 int streamTypeAlias = mStreamVolumeAlias[streamType];
1138 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001139
1140 final int device = getDeviceForStream(streamType);
1141 int oldIndex;
1142
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001143 // skip a2dp absolute volume control request when the device
1144 // is not an a2dp device
1145 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1146 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1147 return;
1148 }
1149
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001150 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1151 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1152 return;
1153 }
1154
Eric Laurentfde16d52012-12-03 14:42:39 -08001155 synchronized (mSafeMediaVolumeState) {
1156 // reset any pending volume command
1157 mPendingVolumeCommand = null;
1158
Eric Laurent42b041e2013-03-29 11:36:03 -07001159 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001160
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001161 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001162
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001163 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1164 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1165 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1166 synchronized (mA2dpAvrcpLock) {
1167 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001168 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001169 }
John Du5a0cf7a2013-07-19 11:30:34 -07001170 }
1171 }
1172
Eric Laurent212532b2014-07-21 15:43:18 -07001173 if (mHdmiManager != null) {
1174 synchronized (mHdmiManager) {
1175 if (mHdmiTvClient != null &&
1176 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1177 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1178 oldIndex != index) {
1179 int maxIndex = getStreamMaxVolume(streamType);
1180 synchronized (mHdmiTvClient) {
1181 if (mHdmiSystemAudioSupported) {
1182 mHdmiTvClient.setSystemAudioVolume(
1183 (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
1184 }
1185 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001186 }
1187 }
1188 }
1189
Eric Laurentfde16d52012-12-03 14:42:39 -08001190 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001191 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001192 ((device & mFixedVolumeDevices) != 0)) {
1193 flags |= AudioManager.FLAG_FIXED_VOLUME;
1194
1195 // volume is either 0 or max allowed for fixed volume devices
1196 if (index != 0) {
1197 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1198 (device & mSafeMediaVolumeDevices) != 0) {
1199 index = mSafeMediaVolumeIndex;
1200 } else {
1201 index = streamState.getMaxIndex();
1202 }
1203 }
1204 }
1205
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001206 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001207 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001208 mPendingVolumeCommand = new StreamVolumeCommand(
1209 streamType, index, flags, device);
1210 } else {
1211 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001212 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001213 }
1214 }
Eric Laurent25101b02011-02-02 09:33:30 -08001215 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 }
1217
Eric Laurent45c90ce2012-04-24 18:44:22 -07001218 /** @see AudioManager#forceVolumeControlStream(int) */
1219 public void forceVolumeControlStream(int streamType, IBinder cb) {
1220 synchronized(mForceControlStreamLock) {
1221 mVolumeControlStream = streamType;
1222 if (mVolumeControlStream == -1) {
1223 if (mForceControlStreamClient != null) {
1224 mForceControlStreamClient.release();
1225 mForceControlStreamClient = null;
1226 }
1227 } else {
1228 mForceControlStreamClient = new ForceControlStreamClient(cb);
1229 }
1230 }
1231 }
1232
1233 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1234 private IBinder mCb; // To be notified of client's death
1235
1236 ForceControlStreamClient(IBinder cb) {
1237 if (cb != null) {
1238 try {
1239 cb.linkToDeath(this, 0);
1240 } catch (RemoteException e) {
1241 // Client has died!
1242 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1243 cb = null;
1244 }
1245 }
1246 mCb = cb;
1247 }
1248
1249 public void binderDied() {
1250 synchronized(mForceControlStreamLock) {
1251 Log.w(TAG, "SCO client died");
1252 if (mForceControlStreamClient != this) {
1253 Log.w(TAG, "unregistered control stream client died");
1254 } else {
1255 mForceControlStreamClient = null;
1256 mVolumeControlStream = -1;
1257 }
1258 }
1259 }
1260
1261 public void release() {
1262 if (mCb != null) {
1263 mCb.unlinkToDeath(this, 0);
1264 mCb = null;
1265 }
1266 }
1267 }
1268
Lei Zhang6c798972012-03-02 11:40:12 -08001269 private int findVolumeDelta(int direction, int volume) {
1270 int delta = 0;
1271 if (direction == AudioManager.ADJUST_RAISE) {
1272 if (volume == MAX_MASTER_VOLUME) {
1273 return 0;
1274 }
1275 // This is the default value if we make it to the end
1276 delta = mMasterVolumeRamp[1];
1277 // If we're raising the volume move down the ramp array until we
1278 // find the volume we're above and use that groups delta.
1279 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1280 if (volume >= mMasterVolumeRamp[i - 1]) {
1281 delta = mMasterVolumeRamp[i];
1282 break;
1283 }
1284 }
1285 } else if (direction == AudioManager.ADJUST_LOWER){
1286 if (volume == 0) {
1287 return 0;
1288 }
1289 int length = mMasterVolumeRamp.length;
1290 // This is the default value if we make it to the end
1291 delta = -mMasterVolumeRamp[length - 1];
1292 // If we're lowering the volume move up the ramp array until we
1293 // find the volume we're below and use the group below it's delta
1294 for (int i = 2; i < length; i += 2) {
1295 if (volume <= mMasterVolumeRamp[i]) {
1296 delta = -mMasterVolumeRamp[i - 1];
1297 break;
1298 }
1299 }
1300 }
1301 return delta;
1302 }
1303
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001304 private void sendBroadcastToAll(Intent intent) {
1305 final long ident = Binder.clearCallingIdentity();
1306 try {
1307 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1308 } finally {
1309 Binder.restoreCallingIdentity(ident);
1310 }
1311 }
1312
1313 private void sendStickyBroadcastToAll(Intent intent) {
1314 final long ident = Binder.clearCallingIdentity();
1315 try {
1316 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1317 } finally {
1318 Binder.restoreCallingIdentity(ident);
1319 }
1320 }
1321
Eric Laurent25101b02011-02-02 09:33:30 -08001322 // UI update and Broadcast Intent
1323 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001324 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001325 streamType = AudioSystem.STREAM_NOTIFICATION;
1326 }
1327
John Spurlock3346a802014-05-20 16:25:37 -04001328 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001329
Eric Laurent4bbcc652012-09-24 14:26:30 -07001330 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1331 oldIndex = (oldIndex + 5) / 10;
1332 index = (index + 5) / 10;
1333 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1334 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1335 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1336 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1337 sendBroadcastToAll(intent);
1338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 }
1340
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001341 // UI update and Broadcast Intent
1342 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
John Spurlock3346a802014-05-20 16:25:37 -04001343 mVolumeController.postMasterVolumeChanged(flags);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001344
1345 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1346 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1347 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001348 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001349 }
1350
1351 // UI update and Broadcast Intent
1352 private void sendMasterMuteUpdate(boolean muted, int flags) {
John Spurlock3346a802014-05-20 16:25:37 -04001353 mVolumeController.postMasterMuteChanged(flags);
Justin Koh57978ed2012-04-03 17:37:58 -07001354 broadcastMasterMuteStatus(muted);
1355 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001356
Justin Koh57978ed2012-04-03 17:37:58 -07001357 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001358 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1359 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001360 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1361 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001362 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001363 }
1364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 * Sets the stream state's index, and posts a message to set system volume.
1367 * This will not call out to the UI. Assumes a valid stream type.
1368 *
1369 * @param streamType Type of the stream
1370 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001371 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 * @param force If true, set the volume even if the desired volume is same
1373 * as the current volume.
1374 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001375 private void setStreamVolumeInt(int streamType,
1376 int index,
1377 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001378 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001380
Eric Laurent42b041e2013-03-29 11:36:03 -07001381 if (streamState.setIndex(index, device) || force) {
1382 // Post message to set system volume (it in turn will post a message
1383 // to persist).
1384 sendMsg(mAudioHandler,
1385 MSG_SET_DEVICE_VOLUME,
1386 SENDMSG_QUEUE,
1387 device,
1388 0,
1389 streamState,
1390 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 }
1392 }
1393
1394 /** @see AudioManager#setStreamSolo(int, boolean) */
1395 public void setStreamSolo(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001396 if (mUseFixedVolume) {
1397 return;
1398 }
1399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 for (int stream = 0; stream < mStreamStates.length; stream++) {
1401 if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 mStreamStates[stream].mute(cb, state);
1403 }
1404 }
1405
1406 /** @see AudioManager#setStreamMute(int, boolean) */
1407 public void setStreamMute(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001408 if (mUseFixedVolume) {
1409 return;
1410 }
1411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 if (isStreamAffectedByMute(streamType)) {
Eric Laurent212532b2014-07-21 15:43:18 -07001413 if (mHdmiManager != null) {
1414 synchronized (mHdmiManager) {
1415 if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
1416 synchronized (mHdmiTvClient) {
1417 if (mHdmiSystemAudioSupported) {
1418 mHdmiTvClient.setSystemAudioMute(state);
1419 }
1420 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001421 }
1422 }
1423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 mStreamStates[streamType].mute(cb, state);
1425 }
1426 }
1427
Eric Laurent25101b02011-02-02 09:33:30 -08001428 /** get stream mute state. */
1429 public boolean isStreamMute(int streamType) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001430 return mStreamStates[streamType].isMuted();
Eric Laurent25101b02011-02-02 09:33:30 -08001431 }
1432
Dianne Hackborn961cae92013-03-20 14:59:43 -07001433 /** @see AudioManager#setMasterMute(boolean, int) */
Julia Reynolds4a21b252014-06-04 11:11:43 -04001434 public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001435 if (mUseFixedVolume) {
1436 return;
1437 }
1438
Julia Reynolds4a21b252014-06-04 11:11:43 -04001439 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1440 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1441 return;
1442 }
1443
Jason Simmons1ce5b262012-02-02 13:00:17 -08001444 if (state != AudioSystem.getMasterMute()) {
1445 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001446 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001447 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Justin Koh57978ed2012-04-03 17:37:58 -07001448 : 0, 0, null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001449 sendMasterMuteUpdate(state, flags);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001450 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001451 }
1452
1453 /** get master mute state. */
1454 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001455 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001456 }
1457
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001458 protected static int getMaxStreamVolume(int streamType) {
1459 return MAX_STREAM_VOLUME[streamType];
1460 }
1461
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 /** @see AudioManager#getStreamVolume(int) */
1463 public int getStreamVolume(int streamType) {
1464 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001465 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001466 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001467
Eric Laurent42b041e2013-03-29 11:36:03 -07001468 // by convention getStreamVolume() returns 0 when a stream is muted.
1469 if (mStreamStates[streamType].isMuted()) {
1470 index = 0;
1471 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001472 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
Eric Laurent4bbcc652012-09-24 14:26:30 -07001473 (device & mFixedVolumeDevices) != 0) {
1474 index = mStreamStates[streamType].getMaxIndex();
Eric Laurent4bbcc652012-09-24 14:26:30 -07001475 }
1476 return (index + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 }
1478
Mike Lockwood47676902011-11-08 10:31:21 -08001479 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001480 if (isMasterMute()) return 0;
1481 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001482 }
1483
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001484 public void setMasterVolume(int volume, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001485 if (mUseFixedVolume) {
1486 return;
1487 }
1488
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001489 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1490 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1491 return;
1492 }
1493
Mike Lockwood97606472012-02-09 11:24:10 -08001494 if (volume < 0) {
1495 volume = 0;
1496 } else if (volume > MAX_MASTER_VOLUME) {
1497 volume = MAX_MASTER_VOLUME;
1498 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001499 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1500 }
1501
1502 private void doSetMasterVolume(float volume, int flags) {
1503 // don't allow changing master volume when muted
1504 if (!AudioSystem.getMasterMute()) {
1505 int oldVolume = getMasterVolume();
1506 AudioSystem.setMasterVolume(volume);
1507
1508 int newVolume = getMasterVolume();
1509 if (newVolume != oldVolume) {
1510 // Post a persist master volume msg
1511 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1512 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001513 }
Justin Koh3caba512012-04-02 15:32:18 -07001514 // Send the volume update regardless whether there was a change.
1515 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001516 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001517 }
1518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 /** @see AudioManager#getStreamMaxVolume(int) */
1520 public int getStreamMaxVolume(int streamType) {
1521 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001522 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 }
1524
Mike Lockwood47676902011-11-08 10:31:21 -08001525 public int getMasterMaxVolume() {
1526 return MAX_MASTER_VOLUME;
1527 }
Eric Laurent25101b02011-02-02 09:33:30 -08001528
1529 /** Get last audible volume before stream was muted. */
1530 public int getLastAudibleStreamVolume(int streamType) {
1531 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001532 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001533 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001534 }
1535
Mike Lockwoodce952c82011-11-14 10:47:42 -08001536 /** Get last audible master volume before it was muted. */
1537 public int getLastAudibleMasterVolume() {
1538 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1539 }
1540
Dianne Hackborn961cae92013-03-20 14:59:43 -07001541 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001542 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001543 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001544 }
1545
Emily Bernier22c921a2014-05-28 11:01:32 -04001546 /** @see AudioManager#setMicrophoneMute(boolean) */
1547 public void setMicrophoneMute(boolean on, String callingPackage) {
1548 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1549 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1550 return;
1551 }
1552
1553 AudioSystem.muteMicrophone(on);
1554 }
1555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 /** @see AudioManager#getRingerMode() */
1557 public int getRingerMode() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001558 synchronized(mSettingsLock) {
1559 return mRingerMode;
1560 }
1561 }
1562
1563 private void ensureValidRingerMode(int ringerMode) {
1564 if (!AudioManager.isValidRingerMode(ringerMode)) {
1565 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
1568
1569 /** @see AudioManager#setRingerMode(int) */
1570 public void setRingerMode(int ringerMode) {
Eric Laurent212532b2014-07-21 15:43:18 -07001571 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001572 return;
1573 }
1574
Eric Laurent24482012012-05-10 09:41:17 -07001575 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1576 ringerMode = AudioManager.RINGER_MODE_SILENT;
1577 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001578 if (ringerMode != getRingerMode()) {
1579 setRingerModeInt(ringerMode, true);
1580 // Send sticky broadcast
1581 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 }
1583 }
1584
Eric Laurent4050c932009-07-08 02:52:14 -07001585 private void setRingerModeInt(int ringerMode, boolean persist) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001586 synchronized(mSettingsLock) {
1587 mRingerMode = ringerMode;
1588 }
Jason Parekhb1096152009-03-24 17:48:25 -07001589
Eric Laurent5b4e6542010-03-19 20:02:21 -07001590 // Mute stream if not previously muted by ringer mode and ringer mode
1591 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1592 // Unmute stream if previously muted by ringer mode and ringer mode
1593 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001594 int numStreamTypes = AudioSystem.getNumStreamTypes();
Eric Laurent5b4e6542010-03-19 20:02:21 -07001595 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1596 if (isStreamMutedByRingerMode(streamType)) {
1597 if (!isStreamAffectedByRingerMode(streamType) ||
Glenn Kastenba195eb2011-12-13 09:30:40 -08001598 ringerMode == AudioManager.RINGER_MODE_NORMAL) {
Eric Laurentb024c302011-10-14 17:19:27 -07001599 // ring and notifications volume should never be 0 when not silenced
1600 // on voice capable devices
Eric Laurent212532b2014-07-21 15:43:18 -07001601 if (isPlatformVoice() &&
Eric Laurent6d517662012-04-23 18:42:39 -07001602 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07001603 synchronized (mStreamStates[streamType]) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001604 Set set = mStreamStates[streamType].mIndex.entrySet();
Eric Laurent3172d5e2012-05-09 11:38:16 -07001605 Iterator i = set.iterator();
1606 while (i.hasNext()) {
1607 Map.Entry entry = (Map.Entry)i.next();
1608 if ((Integer)entry.getValue() == 0) {
1609 entry.setValue(10);
1610 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001611 }
1612 }
Eric Laurentb024c302011-10-14 17:19:27 -07001613 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001614 mStreamStates[streamType].mute(null, false);
1615 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent9bcf4012009-06-12 06:09:28 -07001616 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001617 } else {
1618 if (isStreamAffectedByRingerMode(streamType) &&
Glenn Kastenba195eb2011-12-13 09:30:40 -08001619 ringerMode != AudioManager.RINGER_MODE_NORMAL) {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001620 mStreamStates[streamType].mute(null, true);
1621 mRingerModeMutedStreams |= (1 << streamType);
1622 }
Jason Parekhb1096152009-03-24 17:48:25 -07001623 }
1624 }
Eric Laurenta553c252009-07-17 12:17:14 -07001625
Jason Parekhb1096152009-03-24 17:48:25 -07001626 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001627 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001628 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001629 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1630 }
Jason Parekhb1096152009-03-24 17:48:25 -07001631 }
1632
Mike Lockwood90631542012-01-06 11:20:37 -05001633 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001634 if (mUseFixedVolume) {
1635 AudioSystem.setMasterVolume(1.0f);
1636 return;
1637 }
Mike Lockwood90631542012-01-06 11:20:37 -05001638 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001639 float volume = Settings.System.getFloatForUser(mContentResolver,
1640 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001641 if (volume >= 0.0f) {
1642 AudioSystem.setMasterVolume(volume);
1643 }
1644 }
1645 }
1646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 /** @see AudioManager#shouldVibrate(int) */
1648 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001649 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650
1651 switch (getVibrateSetting(vibrateType)) {
1652
1653 case AudioManager.VIBRATE_SETTING_ON:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001654 return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655
1656 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001657 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658
1659 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001660 // return false, even for incoming calls
1661 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662
1663 default:
1664 return false;
1665 }
1666 }
1667
1668 /** @see AudioManager#getVibrateSetting(int) */
1669 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001670 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1672 }
1673
1674 /** @see AudioManager#setVibrateSetting(int, int) */
1675 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1676
Eric Laurentbffc3d12012-05-07 17:43:49 -07001677 if (!mHasVibrator) return;
1678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1680
1681 // Broadcast change
1682 broadcastVibrateSetting(vibrateType);
1683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 }
1685
1686 /**
1687 * @see #setVibrateSetting(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 */
1689 public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1690 int vibrateSetting) {
1691
1692 // First clear the existing setting. Each vibrate type has two bits in
1693 // the value. Note '3' is '11' in binary.
1694 existingValue &= ~(3 << (vibrateType * 2));
1695
1696 // Set into the old value
1697 existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1698
1699 return existingValue;
1700 }
1701
Eric Laurent9272b4b2010-01-23 17:12:59 -08001702 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1703 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001704 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001705 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1706
Eric Laurent9f103de2011-09-08 15:04:23 -07001707 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001708 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001709 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001710 }
1711
1712 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001713 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001714 synchronized(mSetModeDeathHandlers) {
1715 Log.w(TAG, "setMode() client died");
1716 int index = mSetModeDeathHandlers.indexOf(this);
1717 if (index < 0) {
1718 Log.w(TAG, "unregistered setMode() client died");
1719 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001720 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001721 }
1722 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001723 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1724 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001725 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001726 final long ident = Binder.clearCallingIdentity();
1727 disconnectBluetoothSco(newModeOwnerPid);
1728 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001729 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001730 }
1731
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001732 public int getPid() {
1733 return mPid;
1734 }
1735
Eric Laurent9272b4b2010-01-23 17:12:59 -08001736 public void setMode(int mode) {
1737 mMode = mode;
1738 }
1739
1740 public int getMode() {
1741 return mMode;
1742 }
1743
1744 public IBinder getBinder() {
1745 return mCb;
1746 }
1747 }
1748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001750 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001751 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 if (!checkAudioSettingsPermission("setMode()")) {
1753 return;
1754 }
Eric Laurenta553c252009-07-17 12:17:14 -07001755
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001756 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001757 return;
1758 }
1759
Eric Laurentd7454be2011-09-14 08:45:58 -07001760 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001761 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001762 if (mode == AudioSystem.MODE_CURRENT) {
1763 mode = mMode;
1764 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001765 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001766 }
1767 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1768 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001769 if (newModeOwnerPid != 0) {
1770 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001771 }
1772 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001773
Eric Laurent9f103de2011-09-08 15:04:23 -07001774 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001775 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001776 // any mode other than NORMAL.
Eric Laurentd7454be2011-09-14 08:45:58 -07001777 int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001778 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07001779 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001780 if (cb == null) {
1781 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001782 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001783 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001784
Eric Laurent9f103de2011-09-08 15:04:23 -07001785 SetModeDeathHandler hdlr = null;
1786 Iterator iter = mSetModeDeathHandlers.iterator();
1787 while (iter.hasNext()) {
1788 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1789 if (h.getPid() == pid) {
1790 hdlr = h;
1791 // Remove from client list so that it is re-inserted at top of list
1792 iter.remove();
1793 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1794 break;
1795 }
1796 }
1797 int status = AudioSystem.AUDIO_STATUS_OK;
1798 do {
1799 if (mode == AudioSystem.MODE_NORMAL) {
1800 // get new mode from client at top the list if any
1801 if (!mSetModeDeathHandlers.isEmpty()) {
1802 hdlr = mSetModeDeathHandlers.get(0);
1803 cb = hdlr.getBinder();
1804 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001805 if (DEBUG_MODE) {
1806 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
1807 + hdlr.mPid);
1808 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07001809 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001810 } else {
1811 if (hdlr == null) {
1812 hdlr = new SetModeDeathHandler(cb, pid);
1813 }
1814 // Register for client death notification
1815 try {
1816 cb.linkToDeath(hdlr, 0);
1817 } catch (RemoteException e) {
1818 // Client has died!
1819 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1820 }
1821
1822 // Last client to call setMode() is always at top of client list
1823 // as required by SetModeDeathHandler.binderDied()
1824 mSetModeDeathHandlers.add(0, hdlr);
1825 hdlr.setMode(mode);
1826 }
1827
1828 if (mode != mMode) {
1829 status = AudioSystem.setPhoneState(mode);
1830 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001831 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001832 mMode = mode;
1833 } else {
1834 if (hdlr != null) {
1835 mSetModeDeathHandlers.remove(hdlr);
1836 cb.unlinkToDeath(hdlr, 0);
1837 }
1838 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001839 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001840 mode = AudioSystem.MODE_NORMAL;
1841 }
1842 } else {
1843 status = AudioSystem.AUDIO_STATUS_OK;
1844 }
1845 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1846
1847 if (status == AudioSystem.AUDIO_STATUS_OK) {
1848 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07001849 if (mSetModeDeathHandlers.isEmpty()) {
1850 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1851 } else {
1852 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 }
1855 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001856 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001857 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1858 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07001859
1860 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001862 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 }
1864
1865 /** @see AudioManager#getMode() */
1866 public int getMode() {
1867 return mMode;
1868 }
1869
Eric Laurente78fced2013-03-15 16:03:47 -07001870 //==========================================================================================
1871 // Sound Effects
1872 //==========================================================================================
1873
1874 private static final String TAG_AUDIO_ASSETS = "audio_assets";
1875 private static final String ATTR_VERSION = "version";
1876 private static final String TAG_GROUP = "group";
1877 private static final String ATTR_GROUP_NAME = "name";
1878 private static final String TAG_ASSET = "asset";
1879 private static final String ATTR_ASSET_ID = "id";
1880 private static final String ATTR_ASSET_FILE = "file";
1881
1882 private static final String ASSET_FILE_VERSION = "1.0";
1883 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1884
Glenn Kasten167d1a22013-07-23 16:24:41 -07001885 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001886
1887 class LoadSoundEffectReply {
1888 public int mStatus = 1;
1889 };
1890
Eric Laurente78fced2013-03-15 16:03:47 -07001891 private void loadTouchSoundAssetDefaults() {
1892 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1893 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1894 SOUND_EFFECT_FILES_MAP[i][0] = 0;
1895 SOUND_EFFECT_FILES_MAP[i][1] = -1;
1896 }
1897 }
1898
1899 private void loadTouchSoundAssets() {
1900 XmlResourceParser parser = null;
1901
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001902 // only load assets once.
1903 if (!SOUND_EFFECT_FILES.isEmpty()) {
1904 return;
1905 }
1906
Eric Laurente78fced2013-03-15 16:03:47 -07001907 loadTouchSoundAssetDefaults();
1908
1909 try {
1910 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1911
1912 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1913 String version = parser.getAttributeValue(null, ATTR_VERSION);
1914 boolean inTouchSoundsGroup = false;
1915
1916 if (ASSET_FILE_VERSION.equals(version)) {
1917 while (true) {
1918 XmlUtils.nextElement(parser);
1919 String element = parser.getName();
1920 if (element == null) {
1921 break;
1922 }
1923 if (element.equals(TAG_GROUP)) {
1924 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1925 if (GROUP_TOUCH_SOUNDS.equals(name)) {
1926 inTouchSoundsGroup = true;
1927 break;
1928 }
1929 }
1930 }
1931 while (inTouchSoundsGroup) {
1932 XmlUtils.nextElement(parser);
1933 String element = parser.getName();
1934 if (element == null) {
1935 break;
1936 }
1937 if (element.equals(TAG_ASSET)) {
1938 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1939 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1940 int fx;
1941
1942 try {
1943 Field field = AudioManager.class.getField(id);
1944 fx = field.getInt(null);
1945 } catch (Exception e) {
1946 Log.w(TAG, "Invalid touch sound ID: "+id);
1947 continue;
1948 }
1949
1950 int i = SOUND_EFFECT_FILES.indexOf(file);
1951 if (i == -1) {
1952 i = SOUND_EFFECT_FILES.size();
1953 SOUND_EFFECT_FILES.add(file);
1954 }
1955 SOUND_EFFECT_FILES_MAP[fx][0] = i;
1956 } else {
1957 break;
1958 }
1959 }
1960 }
1961 } catch (Resources.NotFoundException e) {
1962 Log.w(TAG, "audio assets file not found", e);
1963 } catch (XmlPullParserException e) {
1964 Log.w(TAG, "XML parser exception reading touch sound assets", e);
1965 } catch (IOException e) {
1966 Log.w(TAG, "I/O exception reading touch sound assets", e);
1967 } finally {
1968 if (parser != null) {
1969 parser.close();
1970 }
1971 }
1972 }
1973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 /** @see AudioManager#playSoundEffect(int) */
1975 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001976 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 }
1978
1979 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07001981 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1982 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1983 return;
1984 }
1985
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001986 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 effectType, (int) (volume * 1000), null, 0);
1988 }
1989
1990 /**
1991 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08001992 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 */
1994 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001995 int attempts = 3;
1996 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08001997
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001998 synchronized (reply) {
1999 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2000 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002001 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002002 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002003 } catch (InterruptedException e) {
2004 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002005 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002008 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 }
2010
2011 /**
2012 * Unloads samples from the sound pool.
2013 * This method can be called to free some memory when
2014 * sound effects are disabled.
2015 */
2016 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002017 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 }
2019
Eric Laurenta60e2122010-12-28 16:49:07 -08002020 class SoundPoolListenerThread extends Thread {
2021 public SoundPoolListenerThread() {
2022 super("SoundPoolListenerThread");
2023 }
2024
2025 @Override
2026 public void run() {
2027
2028 Looper.prepare();
2029 mSoundPoolLooper = Looper.myLooper();
2030
2031 synchronized (mSoundEffectsLock) {
2032 if (mSoundPool != null) {
2033 mSoundPoolCallBack = new SoundPoolCallback();
2034 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2035 }
2036 mSoundEffectsLock.notify();
2037 }
2038 Looper.loop();
2039 }
2040 }
2041
2042 private final class SoundPoolCallback implements
2043 android.media.SoundPool.OnLoadCompleteListener {
2044
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002045 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2046 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002047
2048 public int status() {
2049 return mStatus;
2050 }
2051
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002052 public void setSamples(int[] samples) {
2053 for (int i = 0; i < samples.length; i++) {
2054 // do not wait ack for samples rejected upfront by SoundPool
2055 if (samples[i] > 0) {
2056 mSamples.add(samples[i]);
2057 }
2058 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002059 }
2060
2061 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2062 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002063 int i = mSamples.indexOf(sampleId);
2064 if (i >= 0) {
2065 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002066 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002067 if ((status != 0) || mSamples. isEmpty()) {
2068 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002069 mSoundEffectsLock.notify();
2070 }
2071 }
2072 }
2073 }
2074
Eric Laurent4050c932009-07-08 02:52:14 -07002075 /** @see AudioManager#reloadAudioSettings() */
2076 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002077 readAudioSettings(false /*userSwitch*/);
2078 }
2079
2080 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002081 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2082 readPersistedSettings();
2083
2084 // restore volume settings
2085 int numStreamTypes = AudioSystem.getNumStreamTypes();
2086 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2087 VolumeStreamState streamState = mStreamStates[streamType];
2088
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002089 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2090 continue;
2091 }
2092
Eric Laurent3172d5e2012-05-09 11:38:16 -07002093 synchronized (streamState) {
2094 streamState.readSettings();
Eric Laurenta553c252009-07-17 12:17:14 -07002095
Eric Laurent3172d5e2012-05-09 11:38:16 -07002096 // unmute stream that was muted but is not affect by mute anymore
Eric Laurent42b041e2013-03-29 11:36:03 -07002097 if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002098 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002099 int size = streamState.mDeathHandlers.size();
2100 for (int i = 0; i < size; i++) {
2101 streamState.mDeathHandlers.get(i).mMuteCount = 1;
2102 streamState.mDeathHandlers.get(i).mute(false);
2103 }
Eric Laurent4050c932009-07-08 02:52:14 -07002104 }
Eric Laurent4050c932009-07-08 02:52:14 -07002105 }
2106 }
2107
Eric Laurent33902db2012-10-07 16:15:07 -07002108 // apply new ringer mode before checking volume for alias streams so that streams
2109 // muted by ringer mode have the correct volume
2110 setRingerModeInt(getRingerMode(), false);
2111
Eric Laurent212532b2014-07-21 15:43:18 -07002112 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002113 checkAllAliasStreamVolumes();
2114
Eric Laurentd640bd32012-09-28 18:01:48 -07002115 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002116 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2117 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2118 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002119 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002120 enforceSafeMediaVolume();
2121 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002122 }
Eric Laurent4050c932009-07-08 02:52:14 -07002123 }
2124
Dianne Hackborn961cae92013-03-20 14:59:43 -07002125 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002126 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002127 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2128 return;
2129 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002130
2131 if (on) {
2132 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2133 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2134 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2135 }
2136 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2137 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2138 mForcedUseForComm = AudioSystem.FORCE_NONE;
2139 }
Eric Laurentfa640152011-03-12 15:59:51 -08002140
Eric Laurentafbb0472011-12-15 09:04:23 -08002141 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002142 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002143 }
2144
2145 /** @see AudioManager#isSpeakerphoneOn() */
2146 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002147 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002148 }
2149
Dianne Hackborn961cae92013-03-20 14:59:43 -07002150 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002151 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002152 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2153 return;
2154 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002155
2156 if (on) {
2157 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2158 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2159 mForcedUseForComm = AudioSystem.FORCE_NONE;
2160 }
Eric Laurentfa640152011-03-12 15:59:51 -08002161
Eric Laurentafbb0472011-12-15 09:04:23 -08002162 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002163 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002164 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002165 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002166 }
2167
2168 /** @see AudioManager#isBluetoothScoOn() */
2169 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002170 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002171 }
2172
Dianne Hackborn961cae92013-03-20 14:59:43 -07002173 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002174 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002175 synchronized (mBluetoothA2dpEnabledLock) {
2176 mBluetoothA2dpEnabled = on;
2177 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2178 AudioSystem.FOR_MEDIA,
2179 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2180 null, 0);
2181 }
Eric Laurent78472112012-05-21 08:57:21 -07002182 }
2183
2184 /** @see AudioManager#isBluetoothA2dpOn() */
2185 public boolean isBluetoothA2dpOn() {
2186 synchronized (mBluetoothA2dpEnabledLock) {
2187 return mBluetoothA2dpEnabled;
2188 }
2189 }
2190
Eric Laurent3def1ee2010-03-17 23:26:26 -07002191 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002192 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2193 int scoAudioMode =
2194 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002195 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002196 startBluetoothScoInt(cb, scoAudioMode);
2197 }
2198
2199 /** @see AudioManager#startBluetoothScoVirtualCall() */
2200 public void startBluetoothScoVirtualCall(IBinder cb) {
2201 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2202 }
2203
2204 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002205 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002206 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002207 return;
2208 }
Eric Laurent854938a2011-02-22 12:05:20 -08002209 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002210 // The calling identity must be cleared before calling ScoClient.incCount().
2211 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2212 // and this must be done on behalf of system server to make sure permissions are granted.
2213 // The caller identity must be cleared after getScoClient() because it is needed if a new
2214 // client is created.
2215 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002216 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002217 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002218 }
2219
2220 /** @see AudioManager#stopBluetoothSco() */
2221 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002222 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002223 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002224 return;
2225 }
Eric Laurent854938a2011-02-22 12:05:20 -08002226 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002227 // The calling identity must be cleared before calling ScoClient.decCount().
2228 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2229 // and this must be done on behalf of system server to make sure permissions are granted.
2230 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002231 if (client != null) {
2232 client.decCount();
2233 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002234 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002235 }
2236
Eric Laurent78472112012-05-21 08:57:21 -07002237
Eric Laurent3def1ee2010-03-17 23:26:26 -07002238 private class ScoClient implements IBinder.DeathRecipient {
2239 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002240 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002241 private int mStartcount; // number of SCO connections started by this client
2242
2243 ScoClient(IBinder cb) {
2244 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002245 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002246 mStartcount = 0;
2247 }
2248
2249 public void binderDied() {
2250 synchronized(mScoClients) {
2251 Log.w(TAG, "SCO client died");
2252 int index = mScoClients.indexOf(this);
2253 if (index < 0) {
2254 Log.w(TAG, "unregistered SCO client died");
2255 } else {
2256 clearCount(true);
2257 mScoClients.remove(this);
2258 }
2259 }
2260 }
2261
Eric Laurent83900752014-05-15 15:14:22 -07002262 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002263 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002264 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002265 if (mStartcount == 0) {
2266 try {
2267 mCb.linkToDeath(this, 0);
2268 } catch (RemoteException e) {
2269 // client has already died!
2270 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2271 }
2272 }
2273 mStartcount++;
2274 }
2275 }
2276
2277 public void decCount() {
2278 synchronized(mScoClients) {
2279 if (mStartcount == 0) {
2280 Log.w(TAG, "ScoClient.decCount() already 0");
2281 } else {
2282 mStartcount--;
2283 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002284 try {
2285 mCb.unlinkToDeath(this, 0);
2286 } catch (NoSuchElementException e) {
2287 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2288 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002289 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002290 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002291 }
2292 }
2293 }
2294
2295 public void clearCount(boolean stopSco) {
2296 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002297 if (mStartcount != 0) {
2298 try {
2299 mCb.unlinkToDeath(this, 0);
2300 } catch (NoSuchElementException e) {
2301 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2302 }
2303 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002304 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002305 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002306 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002307 }
2308 }
2309 }
2310
2311 public int getCount() {
2312 return mStartcount;
2313 }
2314
2315 public IBinder getBinder() {
2316 return mCb;
2317 }
2318
Eric Laurentd7454be2011-09-14 08:45:58 -07002319 public int getPid() {
2320 return mCreatorPid;
2321 }
2322
Eric Laurent3def1ee2010-03-17 23:26:26 -07002323 public int totalCount() {
2324 synchronized(mScoClients) {
2325 int count = 0;
2326 int size = mScoClients.size();
2327 for (int i = 0; i < size; i++) {
2328 count += mScoClients.get(i).getCount();
2329 }
2330 return count;
2331 }
2332 }
2333
Eric Laurent83900752014-05-15 15:14:22 -07002334 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002335 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002336 if (totalCount() == 0) {
2337 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2338 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2339 // the connection.
2340 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2341 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002342 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002343 synchronized(mSetModeDeathHandlers) {
2344 if ((mSetModeDeathHandlers.isEmpty() ||
2345 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2346 (mScoAudioState == SCO_STATE_INACTIVE ||
2347 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2348 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002349 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002350 if (scoAudioMode == SCO_MODE_UNDEFINED) {
2351 mScoAudioMode = new Integer(Settings.Global.getInt(
2352 mContentResolver,
2353 "bluetooth_sco_channel_"+
2354 mBluetoothHeadsetDevice.getAddress(),
2355 SCO_MODE_VIRTUAL_CALL));
2356 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2357 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2358 }
2359 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002360 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002361 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002362 if (mScoAudioMode == SCO_MODE_RAW) {
2363 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002364 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002365 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2366 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002367 } else if (mScoAudioMode == SCO_MODE_VR) {
2368 status = mBluetoothHeadset.startVoiceRecognition(
2369 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002370 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002371
Eric Laurentc18c9132013-04-12 17:24:56 -07002372 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002373 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2374 } else {
2375 broadcastScoConnectionState(
2376 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2377 }
2378 } else if (getBluetoothHeadset()) {
2379 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002380 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002381 } else {
2382 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2383 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002384 }
2385 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002386 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002387 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002388 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002389 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002390 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2391 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2392 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002393 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002394 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002395 if (mScoAudioMode == SCO_MODE_RAW) {
2396 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002397 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002398 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2399 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002400 } else if (mScoAudioMode == SCO_MODE_VR) {
2401 status = mBluetoothHeadset.stopVoiceRecognition(
2402 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002403 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002404
Eric Laurentc18c9132013-04-12 17:24:56 -07002405 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002406 mScoAudioState = SCO_STATE_INACTIVE;
2407 broadcastScoConnectionState(
2408 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2409 }
2410 } else if (getBluetoothHeadset()) {
2411 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2412 }
2413 } else {
2414 mScoAudioState = SCO_STATE_INACTIVE;
2415 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2416 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002417 }
2418 }
2419 }
2420 }
2421
Eric Laurent62ef7672010-11-24 10:58:32 -08002422 private void checkScoAudioState() {
2423 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002424 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002425 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2426 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2427 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2428 }
2429 }
2430
Eric Laurent854938a2011-02-22 12:05:20 -08002431 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002432 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002433 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002434 int size = mScoClients.size();
2435 for (int i = 0; i < size; i++) {
2436 client = mScoClients.get(i);
2437 if (client.getBinder() == cb)
2438 return client;
2439 }
Eric Laurent854938a2011-02-22 12:05:20 -08002440 if (create) {
2441 client = new ScoClient(cb);
2442 mScoClients.add(client);
2443 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002444 return client;
2445 }
2446 }
2447
Eric Laurentd7454be2011-09-14 08:45:58 -07002448 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002449 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002450 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002451 int size = mScoClients.size();
2452 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002453 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002454 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002455 cl.clearCount(stopSco);
2456 } else {
2457 savedClient = cl;
2458 }
2459 }
2460 mScoClients.clear();
2461 if (savedClient != null) {
2462 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002463 }
2464 }
2465 }
2466
Eric Laurentdc03c612011-04-01 10:59:41 -07002467 private boolean getBluetoothHeadset() {
2468 boolean result = false;
2469 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2470 if (adapter != null) {
2471 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2472 BluetoothProfile.HEADSET);
2473 }
2474 // If we could not get a bluetooth headset proxy, send a failure message
2475 // without delay to reset the SCO audio state and clear SCO clients.
2476 // If we could get a proxy, send a delayed failure message that will reset our state
2477 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002478 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002479 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2480 return result;
2481 }
2482
Eric Laurentd7454be2011-09-14 08:45:58 -07002483 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002484 synchronized(mScoClients) {
2485 checkScoAudioState();
2486 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2487 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2488 if (mBluetoothHeadsetDevice != null) {
2489 if (mBluetoothHeadset != null) {
2490 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002491 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002492 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002493 SENDMSG_REPLACE, 0, 0, null, 0);
2494 }
2495 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2496 getBluetoothHeadset()) {
2497 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2498 }
2499 }
2500 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002501 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002502 }
2503 }
2504 }
2505
2506 private void resetBluetoothSco() {
2507 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002508 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002509 mScoAudioState = SCO_STATE_INACTIVE;
2510 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2511 }
2512 }
2513
2514 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002515 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2516 SENDMSG_QUEUE, state, 0, null, 0);
2517 }
2518
2519 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002520 if (state != mScoConnectionState) {
2521 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2522 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2523 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2524 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002525 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002526 mScoConnectionState = state;
2527 }
2528 }
2529
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002530 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2531 new BluetoothProfile.ServiceListener() {
2532 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002533 BluetoothDevice btDevice;
2534 List<BluetoothDevice> deviceList;
2535 switch(profile) {
2536 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002537 synchronized (mA2dpAvrcpLock) {
2538 mA2dp = (BluetoothA2dp) proxy;
2539 deviceList = mA2dp.getConnectedDevices();
2540 if (deviceList.size() > 0) {
2541 btDevice = deviceList.get(0);
2542 synchronized (mConnectedDevices) {
2543 int state = mA2dp.getConnectionState(btDevice);
2544 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002545 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2546 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002547 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002548 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002549 state,
2550 0,
2551 btDevice,
2552 delay);
2553 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002554 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002555 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002556 break;
2557
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002558 case BluetoothProfile.A2DP_SINK:
2559 deviceList = proxy.getConnectedDevices();
2560 if (deviceList.size() > 0) {
2561 btDevice = deviceList.get(0);
2562 synchronized (mConnectedDevices) {
2563 int state = proxy.getConnectionState(btDevice);
2564 queueMsgUnderWakeLock(mAudioHandler,
2565 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2566 state,
2567 0,
2568 btDevice,
2569 0 /* delay */);
2570 }
2571 }
2572 break;
2573
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002574 case BluetoothProfile.HEADSET:
2575 synchronized (mScoClients) {
2576 // Discard timeout message
2577 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2578 mBluetoothHeadset = (BluetoothHeadset) proxy;
2579 deviceList = mBluetoothHeadset.getConnectedDevices();
2580 if (deviceList.size() > 0) {
2581 mBluetoothHeadsetDevice = deviceList.get(0);
2582 } else {
2583 mBluetoothHeadsetDevice = null;
2584 }
2585 // Refresh SCO audio state
2586 checkScoAudioState();
2587 // Continue pending action if any
2588 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2589 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2590 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2591 boolean status = false;
2592 if (mBluetoothHeadsetDevice != null) {
2593 switch (mScoAudioState) {
2594 case SCO_STATE_ACTIVATE_REQ:
2595 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002596 if (mScoAudioMode == SCO_MODE_RAW) {
2597 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002598 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002599 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2600 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002601 } else if (mScoAudioMode == SCO_MODE_VR) {
2602 status = mBluetoothHeadset.startVoiceRecognition(
2603 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002604 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002605 break;
2606 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002607 if (mScoAudioMode == SCO_MODE_RAW) {
2608 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002609 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002610 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2611 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002612 } else if (mScoAudioMode == SCO_MODE_VR) {
2613 status = mBluetoothHeadset.stopVoiceRecognition(
2614 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002615 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002616 break;
2617 case SCO_STATE_DEACTIVATE_EXT_REQ:
2618 status = mBluetoothHeadset.stopVoiceRecognition(
2619 mBluetoothHeadsetDevice);
2620 }
2621 }
2622 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002623 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002624 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002625 }
2626 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002627 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002628 break;
2629
2630 default:
2631 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002632 }
2633 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002634 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002635 switch(profile) {
2636 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002637 synchronized (mA2dpAvrcpLock) {
2638 mA2dp = null;
2639 synchronized (mConnectedDevices) {
2640 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2641 makeA2dpDeviceUnavailableNow(
2642 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2643 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002644 }
2645 }
2646 break;
2647
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002648 case BluetoothProfile.A2DP_SINK:
2649 synchronized (mConnectedDevices) {
2650 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2651 makeA2dpSrcUnavailable(
2652 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2653 }
2654 }
2655 break;
2656
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002657 case BluetoothProfile.HEADSET:
2658 synchronized (mScoClients) {
2659 mBluetoothHeadset = null;
2660 }
2661 break;
2662
2663 default:
2664 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002665 }
2666 }
2667 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002668
Eric Laurentc34dcc12012-09-10 13:51:52 -07002669 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002670 synchronized (mSafeMediaVolumeState) {
2671 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002672 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2673
2674 if ((device & mSafeMediaVolumeDevices) != 0) {
2675 sendMsg(mAudioHandler,
2676 MSG_CHECK_MUSIC_ACTIVE,
2677 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002678 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002679 0,
2680 null,
2681 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002682 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002683 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2684 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002685 // Approximate cumulative active music time
2686 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2687 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2688 setSafeMediaVolumeEnabled(true);
2689 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002690 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002691 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002692 }
2693 }
2694 }
2695 }
2696 }
2697
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002698 private void saveMusicActiveMs() {
2699 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2700 }
2701
Eric Laurentd640bd32012-09-28 18:01:48 -07002702 private void onConfigureSafeVolume(boolean force) {
2703 synchronized (mSafeMediaVolumeState) {
2704 int mcc = mContext.getResources().getConfiguration().mcc;
2705 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2706 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2707 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04002708 boolean safeMediaVolumeEnabled =
2709 SystemProperties.getBoolean("audio.safemedia.force", false)
2710 || mContext.getResources().getBoolean(
2711 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002712
2713 // The persisted state is either "disabled" or "active": this is the state applied
2714 // next time we boot and cannot be "inactive"
2715 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002716 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002717 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2718 // The state can already be "inactive" here if the user has forced it before
2719 // the 30 seconds timeout for forced configuration. In this case we don't reset
2720 // it to "active".
2721 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002722 if (mMusicActiveMs == 0) {
2723 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2724 enforceSafeMediaVolume();
2725 } else {
2726 // We have existing playback time recorded, already confirmed.
2727 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2728 }
Eric Laurent05274f32012-11-29 12:48:18 -08002729 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002730 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002731 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002732 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2733 }
2734 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002735 sendMsg(mAudioHandler,
2736 MSG_PERSIST_SAFE_VOLUME_STATE,
2737 SENDMSG_QUEUE,
2738 persistedState,
2739 0,
2740 null,
2741 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002742 }
2743 }
2744 }
2745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002746 ///////////////////////////////////////////////////////////////////////////
2747 // Internal methods
2748 ///////////////////////////////////////////////////////////////////////////
2749
2750 /**
2751 * Checks if the adjustment should change ringer mode instead of just
2752 * adjusting volume. If so, this will set the proper ringer mode and volume
2753 * indices on the stream states.
2754 */
John Spurlocka11b4af2014-06-01 11:52:23 -04002755 private int checkForRingerModeChange(int oldIndex, int direction, int step) {
2756 int result = FLAG_ADJUST_VOLUME;
Glenn Kastenba195eb2011-12-13 09:30:40 -08002757 int ringerMode = getRingerMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002758
Eric Laurentbffc3d12012-05-07 17:43:49 -07002759 switch (ringerMode) {
2760 case RINGER_MODE_NORMAL:
2761 if (direction == AudioManager.ADJUST_LOWER) {
2762 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002763 // "step" is the delta in internal index units corresponding to a
2764 // change of 1 in UI index units.
2765 // Because of rounding when rescaling from one stream index range to its alias
2766 // index range, we cannot simply test oldIndex == step:
2767 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2768 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002769 ringerMode = RINGER_MODE_VIBRATE;
2770 }
2771 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002772 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002773 if ((oldIndex < step)
2774 && VOLUME_SETS_RINGER_MODE_SILENT
2775 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002776 ringerMode = RINGER_MODE_SILENT;
2777 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002779 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002780 break;
2781 case RINGER_MODE_VIBRATE:
2782 if (!mHasVibrator) {
2783 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2784 "but no vibrator is present");
2785 break;
2786 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002787 if ((direction == AudioManager.ADJUST_LOWER)) {
John Spurlock86005342014-05-23 11:58:00 -04002788 if (VOLUME_SETS_RINGER_MODE_SILENT
2789 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002790 ringerMode = RINGER_MODE_SILENT;
Amith Yamasanic696a532011-10-28 17:02:37 -07002791 }
2792 } else if (direction == AudioManager.ADJUST_RAISE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002793 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002794 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002795 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002796 break;
2797 case RINGER_MODE_SILENT:
Daniel Sandler6329bf72010-02-26 15:17:44 -05002798 if (direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002799 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2800 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002801 } else {
John Spurlocka11b4af2014-06-01 11:52:23 -04002802 if (mHasVibrator) {
2803 ringerMode = RINGER_MODE_VIBRATE;
2804 } else {
2805 ringerMode = RINGER_MODE_NORMAL;
2806 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002807 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05002808 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002809 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002810 break;
2811 default:
2812 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2813 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 }
2815
Eric Laurentbffc3d12012-05-07 17:43:49 -07002816 setRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002817
Eric Laurent25101b02011-02-02 09:33:30 -08002818 mPrevVolDirection = direction;
2819
John Spurlocka11b4af2014-06-01 11:52:23 -04002820 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 }
2822
John Spurlock3346a802014-05-20 16:25:37 -04002823 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07002825 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002826 }
2827
Eric Laurent5b4e6542010-03-19 20:02:21 -07002828 private boolean isStreamMutedByRingerMode(int streamType) {
2829 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2830 }
2831
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002832 boolean updateRingerModeAffectedStreams() {
2833 int ringerModeAffectedStreams;
2834 // make sure settings for ringer mode are consistent with device type: non voice capable
2835 // devices (tablets) include media stream in silent mode whereas phones don't.
2836 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2837 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2838 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2839 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2840 UserHandle.USER_CURRENT);
2841
2842 // ringtone, notification and system streams are always affected by ringer mode
2843 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2844 (1 << AudioSystem.STREAM_NOTIFICATION)|
2845 (1 << AudioSystem.STREAM_SYSTEM);
2846
Eric Laurent212532b2014-07-21 15:43:18 -07002847 switch (mPlatformType) {
Eric Laurent212532b2014-07-21 15:43:18 -07002848 case PLATFORM_TELEVISION:
2849 ringerModeAffectedStreams = 0;
2850 break;
2851 default:
John Spurlock77e54d92014-08-11 12:16:24 -04002852 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07002853 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002854 }
Eric Laurent212532b2014-07-21 15:43:18 -07002855
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002856 synchronized (mCameraSoundForced) {
2857 if (mCameraSoundForced) {
2858 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2859 } else {
2860 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2861 }
2862 }
2863 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2864 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2865 } else {
2866 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2867 }
2868
2869 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2870 Settings.System.putIntForUser(mContentResolver,
2871 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2872 ringerModeAffectedStreams,
2873 UserHandle.USER_CURRENT);
2874 mRingerModeAffectedStreams = ringerModeAffectedStreams;
2875 return true;
2876 }
2877 return false;
2878 }
2879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880 public boolean isStreamAffectedByMute(int streamType) {
2881 return (mMuteAffectedStreams & (1 << streamType)) != 0;
2882 }
2883
2884 private void ensureValidDirection(int direction) {
2885 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2886 throw new IllegalArgumentException("Bad direction " + direction);
2887 }
2888 }
2889
Lei Zhang6c798972012-03-02 11:40:12 -08002890 private void ensureValidSteps(int steps) {
2891 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2892 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2893 }
2894 }
2895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002896 private void ensureValidStreamType(int streamType) {
2897 if (streamType < 0 || streamType >= mStreamStates.length) {
2898 throw new IllegalArgumentException("Bad stream type " + streamType);
2899 }
2900 }
2901
Eric Laurent6d517662012-04-23 18:42:39 -07002902 private boolean isInCommunication() {
Santos Cordon9eb45932014-06-27 12:28:43 -07002903 boolean isInAPhoneCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002904
Santos Cordon9eb45932014-06-27 12:28:43 -07002905 TelecommManager telecommManager =
2906 (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
2907 isInAPhoneCall = telecommManager.isInAPhoneCall();
2908
2909 return (isInAPhoneCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07002910 }
Eric Laurent25101b02011-02-02 09:33:30 -08002911
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002912 /**
2913 * For code clarity for getActiveStreamType(int)
2914 * @param delay_ms max time since last STREAM_MUSIC activity to consider
2915 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2916 * in the last "delay_ms" ms.
2917 */
2918 private boolean isAfMusicActiveRecently(int delay_ms) {
2919 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2920 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2921 }
2922
Eric Laurent6d517662012-04-23 18:42:39 -07002923 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07002924 switch (mPlatformType) {
2925 case PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07002926 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002927 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2928 == AudioSystem.FORCE_BT_SCO) {
2929 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2930 return AudioSystem.STREAM_BLUETOOTH_SCO;
2931 } else {
2932 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2933 return AudioSystem.STREAM_VOICE_CALL;
2934 }
Eric Laurent25101b02011-02-02 09:33:30 -08002935 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002936 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002937 if (DEBUG_VOL)
2938 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2939 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002940 } else {
2941 if (DEBUG_VOL)
2942 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2943 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002944 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002945 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002946 if (DEBUG_VOL)
2947 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2948 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08002949 }
Eric Laurent212532b2014-07-21 15:43:18 -07002950 break;
2951 case PLATFORM_TELEVISION:
2952 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07002953 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07002954 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07002955 }
2956 break;
2957 default:
Eric Laurent6d517662012-04-23 18:42:39 -07002958 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002959 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2960 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002961 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08002962 return AudioSystem.STREAM_BLUETOOTH_SCO;
2963 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002964 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08002965 return AudioSystem.STREAM_VOICE_CALL;
2966 }
2967 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Eric Laurent9903e262012-09-21 18:10:32 -07002968 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002969 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Eric Laurent9903e262012-09-21 18:10:32 -07002970 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002971 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08002972 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002973 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002974 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2975 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2976 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002977 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04002978 if (DEBUG_VOL) Log.v(TAG,
2979 "getActiveStreamType: using STREAM_NOTIFICATION as default");
2980 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002981 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08002982 }
Eric Laurent212532b2014-07-21 15:43:18 -07002983 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002984 }
Eric Laurent212532b2014-07-21 15:43:18 -07002985 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2986 + suggestedStreamType);
2987 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002988 }
2989
Glenn Kastenba195eb2011-12-13 09:30:40 -08002990 private void broadcastRingerMode(int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991 // Send sticky broadcast
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002992 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
Glenn Kastenba195eb2011-12-13 09:30:40 -08002993 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002994 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2995 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002996 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997 }
2998
2999 private void broadcastVibrateSetting(int vibrateType) {
3000 // Send broadcast
3001 if (ActivityManagerNative.isSystemReady()) {
3002 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3003 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3004 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003005 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003006 }
3007 }
3008
3009 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003010 /**
3011 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3012 * Note that the wake lock needs to be released after the message has been handled.
3013 */
3014 private void queueMsgUnderWakeLock(Handler handler, int msg,
3015 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003016 final long ident = Binder.clearCallingIdentity();
3017 // Always acquire the wake lock as AudioService because it is released by the
3018 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003019 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003020 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003021 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023
Eric Laurentafbb0472011-12-15 09:04:23 -08003024 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003025 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003026
3027 if (existingMsgPolicy == SENDMSG_REPLACE) {
3028 handler.removeMessages(msg);
3029 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3030 return;
3031 }
3032
Eric Laurentafbb0472011-12-15 09:04:23 -08003033 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 }
3035
3036 boolean checkAudioSettingsPermission(String method) {
3037 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
3038 == PackageManager.PERMISSION_GRANTED) {
3039 return true;
3040 }
3041 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3042 + Binder.getCallingPid()
3043 + ", uid=" + Binder.getCallingUid();
3044 Log.w(TAG, msg);
3045 return false;
3046 }
3047
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003048 private int getDeviceForStream(int stream) {
3049 int device = AudioSystem.getDevicesForStream(stream);
3050 if ((device & (device - 1)) != 0) {
3051 // Multiple device selection is either:
3052 // - speaker + one other device: give priority to speaker in this case.
3053 // - one A2DP device + another device: happens with duplicated output. In this case
3054 // retain the device on the A2DP output as the other must not correspond to an active
3055 // selection if not the speaker.
3056 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3057 device = AudioSystem.DEVICE_OUT_SPEAKER;
3058 } else {
3059 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3060 }
3061 }
3062 return device;
3063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003065 public void setWiredDeviceConnectionState(int device, int state, String name) {
3066 synchronized (mConnectedDevices) {
3067 int delay = checkSendBecomingNoisyIntent(device, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003068 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003069 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003070 device,
3071 state,
3072 name,
3073 delay);
3074 }
3075 }
3076
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003077 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003078 {
3079 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003080 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3081 throw new IllegalArgumentException("invalid profile " + profile);
3082 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003083 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003084 if (profile == BluetoothProfile.A2DP) {
3085 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3086 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3087 } else {
3088 delay = 0;
3089 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003090 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003091 (profile == BluetoothProfile.A2DP ?
3092 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003093 state,
3094 0,
3095 device,
3096 delay);
3097 }
3098 return delay;
3099 }
3100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 ///////////////////////////////////////////////////////////////////////////
3102 // Inner classes
3103 ///////////////////////////////////////////////////////////////////////////
3104
3105 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003106 private final int mStreamType;
3107
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003108 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003109 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003110 private final ConcurrentHashMap<Integer, Integer> mIndex =
3111 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003112 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113
Eric Laurenta553c252009-07-17 12:17:14 -07003114 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003116 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117
3118 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003119 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003120 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3121 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003122
Eric Laurent33902db2012-10-07 16:15:07 -07003123 // mDeathHandlers must be created before calling readSettings()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 mDeathHandlers = new ArrayList<VolumeDeathHandler>();
Eric Laurent33902db2012-10-07 16:15:07 -07003125
3126 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003127 }
3128
Eric Laurent42b041e2013-03-29 11:36:03 -07003129 public String getSettingNameForDevice(int device) {
3130 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003131 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003132 if (suffix.isEmpty()) {
3133 return name;
3134 }
3135 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003136 }
3137
Eric Laurentfdbee862014-05-12 15:26:12 -07003138 public void readSettings() {
3139 synchronized (VolumeStreamState.class) {
3140 // force maximum volume on all streams if fixed volume property is set
3141 if (mUseFixedVolume) {
3142 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3143 return;
3144 }
3145 // do not read system stream volume from settings: this stream is always aliased
3146 // to another stream type and its volume is never persisted. Values in settings can
3147 // only be stale values
3148 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3149 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
3150 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
3151 synchronized (mCameraSoundForced) {
3152 if (mCameraSoundForced) {
3153 index = mIndexMax;
3154 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003155 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003156 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3157 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003158 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003159
Eric Laurentfdbee862014-05-12 15:26:12 -07003160 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3161
3162 for (int i = 0; remainingDevices != 0; i++) {
3163 int device = (1 << i);
3164 if ((device & remainingDevices) == 0) {
3165 continue;
3166 }
3167 remainingDevices &= ~device;
3168
3169 // retrieve current volume for device
3170 String name = getSettingNameForDevice(device);
3171 // if no volume stored for current stream and device, use default volume if default
3172 // device, continue otherwise
3173 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3174 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3175 int index = Settings.System.getIntForUser(
3176 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3177 if (index == -1) {
3178 continue;
3179 }
3180
Eric Laurent212532b2014-07-21 15:43:18 -07003181 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003182 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 }
3185
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003186 public void applyDeviceVolume(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003187 int index;
3188 if (isMuted()) {
3189 index = 0;
Eric Laurentcd772d02013-10-30 18:31:07 -07003190 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003191 mAvrcpAbsVolSupported) {
3192 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003193 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003194 index = (getIndex(device) + 5)/10;
3195 }
3196 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003198
Eric Laurentfdbee862014-05-12 15:26:12 -07003199 public void applyAllVolumes() {
3200 synchronized (VolumeStreamState.class) {
3201 // apply default volume first: by convention this will reset all
3202 // devices volumes in audio policy manager to the supplied value
3203 int index;
3204 if (isMuted()) {
3205 index = 0;
3206 } else {
3207 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3208 }
3209 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3210 // then apply device specific volumes
3211 Set set = mIndex.entrySet();
3212 Iterator i = set.iterator();
3213 while (i.hasNext()) {
3214 Map.Entry entry = (Map.Entry)i.next();
3215 int device = ((Integer)entry.getKey()).intValue();
3216 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3217 if (isMuted()) {
3218 index = 0;
3219 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3220 mAvrcpAbsVolSupported) {
3221 index = (mIndexMax + 5)/10;
3222 } else {
3223 index = ((Integer)entry.getValue() + 5)/10;
3224 }
3225 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003226 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003227 }
3228 }
3229 }
3230
3231 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003232 return setIndex(getIndex(device) + deltaIndex,
3233 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003234 }
3235
Eric Laurentfdbee862014-05-12 15:26:12 -07003236 public boolean setIndex(int index, int device) {
3237 synchronized (VolumeStreamState.class) {
3238 int oldIndex = getIndex(device);
3239 index = getValidIndex(index);
3240 synchronized (mCameraSoundForced) {
3241 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3242 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003243 }
3244 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003245 mIndex.put(device, index);
3246
3247 if (oldIndex != index) {
3248 // Apply change to all streams using this one as alias
3249 // if changing volume of current device, also change volume of current
3250 // device on aliased stream
3251 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3252 int numStreamTypes = AudioSystem.getNumStreamTypes();
3253 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3254 if (streamType != mStreamType &&
3255 mStreamVolumeAlias[streamType] == mStreamType) {
3256 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3257 mStreamStates[streamType].setIndex(scaledIndex,
3258 device);
3259 if (currentDevice) {
3260 mStreamStates[streamType].setIndex(scaledIndex,
3261 getDeviceForStream(streamType));
3262 }
3263 }
3264 }
3265 return true;
3266 } else {
3267 return false;
3268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 }
3270 }
3271
Eric Laurentfdbee862014-05-12 15:26:12 -07003272 public int getIndex(int device) {
3273 synchronized (VolumeStreamState.class) {
3274 Integer index = mIndex.get(device);
3275 if (index == null) {
3276 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3277 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3278 }
3279 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003280 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003281 }
3282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003284 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
3286
Eric Laurentfdbee862014-05-12 15:26:12 -07003287 public void setAllIndexes(VolumeStreamState srcStream) {
3288 synchronized (VolumeStreamState.class) {
3289 int srcStreamType = srcStream.getStreamType();
3290 // apply default device volume from source stream to all devices first in case
3291 // some devices are present in this stream state but not in source stream state
3292 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003293 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003294 Set set = mIndex.entrySet();
3295 Iterator i = set.iterator();
3296 while (i.hasNext()) {
3297 Map.Entry entry = (Map.Entry)i.next();
3298 entry.setValue(index);
3299 }
3300 // Now apply actual volume for devices in source stream state
3301 set = srcStream.mIndex.entrySet();
3302 i = set.iterator();
3303 while (i.hasNext()) {
3304 Map.Entry entry = (Map.Entry)i.next();
3305 int device = ((Integer)entry.getKey()).intValue();
3306 index = ((Integer)entry.getValue()).intValue();
3307 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003308
Eric Laurentfdbee862014-05-12 15:26:12 -07003309 setIndex(index, device);
3310 }
Eric Laurent6d517662012-04-23 18:42:39 -07003311 }
3312 }
3313
Eric Laurentfdbee862014-05-12 15:26:12 -07003314 public void setAllIndexesToMax() {
3315 synchronized (VolumeStreamState.class) {
3316 Set set = mIndex.entrySet();
3317 Iterator i = set.iterator();
3318 while (i.hasNext()) {
3319 Map.Entry entry = (Map.Entry)i.next();
3320 entry.setValue(mIndexMax);
3321 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003322 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003323 }
3324
Eric Laurentfdbee862014-05-12 15:26:12 -07003325 public void mute(IBinder cb, boolean state) {
3326 synchronized (VolumeStreamState.class) {
3327 VolumeDeathHandler handler = getDeathHandler(cb, state);
3328 if (handler == null) {
3329 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3330 return;
3331 }
3332 handler.mute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 }
3335
Eric Laurent6d517662012-04-23 18:42:39 -07003336 public int getStreamType() {
3337 return mStreamType;
3338 }
3339
Eric Laurent212532b2014-07-21 15:43:18 -07003340 public void checkFixedVolumeDevices() {
3341 synchronized (VolumeStreamState.class) {
3342 // ignore settings for fixed volume devices: volume should always be at max or 0
3343 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3344 Set set = mIndex.entrySet();
3345 Iterator i = set.iterator();
3346 while (i.hasNext()) {
3347 Map.Entry entry = (Map.Entry)i.next();
3348 int device = ((Integer)entry.getKey()).intValue();
3349 int index = ((Integer)entry.getValue()).intValue();
3350 if (((device & mFixedVolumeDevices) != 0) && index != 0) {
3351 entry.setValue(mIndexMax);
3352 }
3353 applyDeviceVolume(device);
3354 }
3355 }
3356 }
3357 }
3358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 private int getValidIndex(int index) {
3360 if (index < 0) {
3361 return 0;
Eric Laurent83a017b2013-03-19 18:15:31 -07003362 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003363 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
3365
3366 return index;
3367 }
3368
3369 private class VolumeDeathHandler implements IBinder.DeathRecipient {
3370 private IBinder mICallback; // To be notified of client's death
3371 private int mMuteCount; // Number of active mutes for this client
3372
3373 VolumeDeathHandler(IBinder cb) {
3374 mICallback = cb;
3375 }
3376
Eric Laurent3172d5e2012-05-09 11:38:16 -07003377 // must be called while synchronized on parent VolumeStreamState
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 public void mute(boolean state) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003379 boolean updateVolume = false;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003380 if (state) {
3381 if (mMuteCount == 0) {
3382 // Register for client death notification
3383 try {
3384 // mICallback can be 0 if muted by AudioService
3385 if (mICallback != null) {
3386 mICallback.linkToDeath(this, 0);
3387 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003388 VolumeStreamState.this.mDeathHandlers.add(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003389 // If the stream is not yet muted by any client, set level to 0
Eric Laurent42b041e2013-03-29 11:36:03 -07003390 if (!VolumeStreamState.this.isMuted()) {
3391 updateVolume = true;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003392 }
3393 } catch (RemoteException e) {
3394 // Client has died!
3395 binderDied();
3396 return;
3397 }
3398 } else {
3399 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3400 }
3401 mMuteCount++;
3402 } else {
3403 if (mMuteCount == 0) {
3404 Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3405 } else {
3406 mMuteCount--;
3407 if (mMuteCount == 0) {
3408 // Unregister from client death notification
Eric Laurent42b041e2013-03-29 11:36:03 -07003409 VolumeStreamState.this.mDeathHandlers.remove(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003410 // mICallback can be 0 if muted by AudioService
3411 if (mICallback != null) {
3412 mICallback.unlinkToDeath(this, 0);
3413 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003414 if (!VolumeStreamState.this.isMuted()) {
3415 updateVolume = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003416 }
3417 }
3418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003419 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003420 if (updateVolume) {
3421 sendMsg(mAudioHandler,
3422 MSG_SET_ALL_VOLUMES,
3423 SENDMSG_QUEUE,
3424 0,
3425 0,
3426 VolumeStreamState.this, 0);
3427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 }
3429
3430 public void binderDied() {
3431 Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3432 if (mMuteCount != 0) {
3433 // Reset all active mute requests from this client.
3434 mMuteCount = 1;
3435 mute(false);
3436 }
3437 }
3438 }
3439
Eric Laurent3172d5e2012-05-09 11:38:16 -07003440 private synchronized int muteCount() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003441 int count = 0;
3442 int size = mDeathHandlers.size();
3443 for (int i = 0; i < size; i++) {
3444 count += mDeathHandlers.get(i).mMuteCount;
3445 }
3446 return count;
3447 }
3448
Eric Laurent42b041e2013-03-29 11:36:03 -07003449 private synchronized boolean isMuted() {
3450 return muteCount() != 0;
3451 }
3452
Eric Laurent3172d5e2012-05-09 11:38:16 -07003453 // only called by mute() which is already synchronized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003454 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003455 VolumeDeathHandler handler;
3456 int size = mDeathHandlers.size();
3457 for (int i = 0; i < size; i++) {
3458 handler = mDeathHandlers.get(i);
3459 if (cb == handler.mICallback) {
3460 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 }
Eric Laurent3172d5e2012-05-09 11:38:16 -07003463 // If this is the first mute request for this client, create a new
3464 // client death handler. Otherwise, it is an out of sequence unmute request.
3465 if (state) {
3466 handler = new VolumeDeathHandler(cb);
3467 } else {
3468 Log.w(TAG, "stream was not muted by this client");
3469 handler = null;
3470 }
3471 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003473
3474 private void dump(PrintWriter pw) {
Eric Laurentdd45d012012-10-08 09:04:34 -07003475 pw.print(" Mute count: ");
3476 pw.println(muteCount());
Eric Laurentbffc3d12012-05-07 17:43:49 -07003477 pw.print(" Current: ");
3478 Set set = mIndex.entrySet();
3479 Iterator i = set.iterator();
3480 while (i.hasNext()) {
3481 Map.Entry entry = (Map.Entry)i.next();
3482 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3483 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3484 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 }
3487
3488 /** Thread that handles native AudioSystem control. */
3489 private class AudioSystemThread extends Thread {
3490 AudioSystemThread() {
3491 super("AudioService");
3492 }
3493
3494 @Override
3495 public void run() {
3496 // Set this thread up so the handler will work on it
3497 Looper.prepare();
3498
3499 synchronized(AudioService.this) {
3500 mAudioHandler = new AudioHandler();
3501
3502 // Notify that the handler has been created
3503 AudioService.this.notify();
3504 }
3505
3506 // Listen for volume change requests that are set by VolumePanel
3507 Looper.loop();
3508 }
3509 }
3510
3511 /** Handles internal volume messages in separate volume thread. */
3512 private class AudioHandler extends Handler {
3513
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003514 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003516 // Apply volume
3517 streamState.applyDeviceVolume(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003518
3519 // Apply change to all streams using this one as alias
3520 int numStreamTypes = AudioSystem.getNumStreamTypes();
3521 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3522 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003523 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurentcd772d02013-10-30 18:31:07 -07003524 // Make sure volume is also maxed out on A2DP device for aliased stream
3525 // that may have a different device selected
3526 int streamDevice = getDeviceForStream(streamType);
3527 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3528 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3529 mStreamStates[streamType].applyDeviceVolume(device);
3530 }
3531 mStreamStates[streamType].applyDeviceVolume(streamDevice);
Eric Laurenta553c252009-07-17 12:17:14 -07003532 }
3533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534
3535 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003536 sendMsg(mAudioHandler,
3537 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003538 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003539 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003540 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003541 streamState,
3542 PERSIST_DELAY);
3543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003544 }
3545
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003546 private void setAllVolumes(VolumeStreamState streamState) {
3547
3548 // Apply volume
3549 streamState.applyAllVolumes();
3550
3551 // Apply change to all streams using this one as alias
3552 int numStreamTypes = AudioSystem.getNumStreamTypes();
3553 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3554 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003555 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003556 mStreamStates[streamType].applyAllVolumes();
3557 }
3558 }
3559 }
3560
Eric Laurent42b041e2013-03-29 11:36:03 -07003561 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003562 if (mUseFixedVolume) {
3563 return;
3564 }
Eric Laurent212532b2014-07-21 15:43:18 -07003565 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3566 return;
3567 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003568 System.putIntForUser(mContentResolver,
3569 streamState.getSettingNameForDevice(device),
3570 (streamState.getIndex(device) + 5)/ 10,
3571 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 }
3573
Glenn Kastenba195eb2011-12-13 09:30:40 -08003574 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003575 if (mUseFixedVolume) {
3576 return;
3577 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003578 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003579 }
3580
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003581 private boolean onLoadSoundEffects() {
3582 int status;
3583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003584 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003585 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003586 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3587 return false;
3588 }
3589
3590 if (mSoundPool != null) {
3591 return true;
3592 }
3593
3594 loadTouchSoundAssets();
3595
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003596 mSoundPool = new SoundPool.Builder()
3597 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3598 .setAudioAttributes(new AudioAttributes.Builder()
3599 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3600 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3601 .build())
3602 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003603 mSoundPoolCallBack = null;
3604 mSoundPoolListenerThread = new SoundPoolListenerThread();
3605 mSoundPoolListenerThread.start();
3606 int attempts = 3;
3607 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3608 try {
3609 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003610 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003611 } catch (InterruptedException e) {
3612 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3613 }
3614 }
3615
3616 if (mSoundPoolCallBack == null) {
3617 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3618 if (mSoundPoolLooper != null) {
3619 mSoundPoolLooper.quit();
3620 mSoundPoolLooper = null;
3621 }
3622 mSoundPoolListenerThread = null;
3623 mSoundPool.release();
3624 mSoundPool = null;
3625 return false;
3626 }
3627 /*
3628 * poolId table: The value -1 in this table indicates that corresponding
3629 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3630 * Once loaded, the value in poolId is the sample ID and the same
3631 * sample can be reused for another effect using the same file.
3632 */
3633 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3634 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3635 poolId[fileIdx] = -1;
3636 }
3637 /*
3638 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3639 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3640 * this indicates we have a valid sample loaded for this effect.
3641 */
3642
3643 int numSamples = 0;
3644 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3645 // Do not load sample if this effect uses the MediaPlayer
3646 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3647 continue;
3648 }
3649 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3650 String filePath = Environment.getRootDirectory()
3651 + SOUND_EFFECTS_PATH
3652 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3653 int sampleId = mSoundPool.load(filePath, 0);
3654 if (sampleId <= 0) {
3655 Log.w(TAG, "Soundpool could not load file: "+filePath);
3656 } else {
3657 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3658 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3659 numSamples++;
3660 }
3661 } else {
3662 SOUND_EFFECT_FILES_MAP[effect][1] =
3663 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3664 }
3665 }
3666 // wait for all samples to be loaded
3667 if (numSamples > 0) {
3668 mSoundPoolCallBack.setSamples(poolId);
3669
3670 attempts = 3;
3671 status = 1;
3672 while ((status == 1) && (attempts-- > 0)) {
3673 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003674 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003675 status = mSoundPoolCallBack.status();
3676 } catch (InterruptedException e) {
3677 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3678 }
3679 }
3680 } else {
3681 status = -1;
3682 }
3683
3684 if (mSoundPoolLooper != null) {
3685 mSoundPoolLooper.quit();
3686 mSoundPoolLooper = null;
3687 }
3688 mSoundPoolListenerThread = null;
3689 if (status != 0) {
3690 Log.w(TAG,
3691 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3692 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3693 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3694 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3695 }
3696 }
3697
3698 mSoundPool.release();
3699 mSoundPool = null;
3700 }
3701 }
3702 return (status == 0);
3703 }
3704
3705 /**
3706 * Unloads samples from the sound pool.
3707 * This method can be called to free some memory when
3708 * sound effects are disabled.
3709 */
3710 private void onUnloadSoundEffects() {
3711 synchronized (mSoundEffectsLock) {
3712 if (mSoundPool == null) {
3713 return;
3714 }
3715
3716 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3717 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3718 poolId[fileIdx] = 0;
3719 }
3720
3721 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3722 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3723 continue;
3724 }
3725 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3726 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3727 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3728 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3729 }
3730 }
3731 mSoundPool.release();
3732 mSoundPool = null;
3733 }
3734 }
3735
3736 private void onPlaySoundEffect(int effectType, int volume) {
3737 synchronized (mSoundEffectsLock) {
3738
3739 onLoadSoundEffects();
3740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741 if (mSoundPool == null) {
3742 return;
3743 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003744 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003745 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003746 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003747 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003748 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003749 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751
3752 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003753 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3754 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 } else {
3756 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003757 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003758 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3759 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003760 mediaPlayer.setDataSource(filePath);
3761 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3762 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003763 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003764 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3765 public void onCompletion(MediaPlayer mp) {
3766 cleanupPlayer(mp);
3767 }
3768 });
3769 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3770 public boolean onError(MediaPlayer mp, int what, int extra) {
3771 cleanupPlayer(mp);
3772 return true;
3773 }
3774 });
3775 mediaPlayer.start();
3776 } catch (IOException ex) {
3777 Log.w(TAG, "MediaPlayer IOException: "+ex);
3778 } catch (IllegalArgumentException ex) {
3779 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3780 } catch (IllegalStateException ex) {
3781 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003782 }
3783 }
3784 }
3785 }
3786
3787 private void cleanupPlayer(MediaPlayer mp) {
3788 if (mp != null) {
3789 try {
3790 mp.stop();
3791 mp.release();
3792 } catch (IllegalStateException ex) {
3793 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3794 }
3795 }
3796 }
3797
Eric Laurentfa640152011-03-12 15:59:51 -08003798 private void setForceUse(int usage, int config) {
3799 AudioSystem.setForceUse(usage, config);
3800 }
3801
Eric Laurent05274f32012-11-29 12:48:18 -08003802 private void onPersistSafeVolumeState(int state) {
3803 Settings.Global.putInt(mContentResolver,
3804 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3805 state);
3806 }
3807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003808 @Override
3809 public void handleMessage(Message msg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003810
Eric Laurentafbb0472011-12-15 09:04:23 -08003811 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003812
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003813 case MSG_SET_DEVICE_VOLUME:
3814 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3815 break;
3816
3817 case MSG_SET_ALL_VOLUMES:
3818 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003819 break;
3820
3821 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07003822 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003823 break;
3824
Mike Lockwood5c55a052011-12-15 17:21:44 -05003825 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07003826 if (mUseFixedVolume) {
3827 return;
3828 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003829 Settings.System.putFloatForUser(mContentResolver,
3830 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07003831 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003832 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05003833 break;
3834
Justin Koh57978ed2012-04-03 17:37:58 -07003835 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07003836 if (mUseFixedVolume) {
3837 return;
3838 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003839 Settings.System.putIntForUser(mContentResolver,
3840 Settings.System.VOLUME_MASTER_MUTE,
3841 msg.arg1,
3842 UserHandle.USER_CURRENT);
Justin Koh57978ed2012-04-03 17:37:58 -07003843 break;
3844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003845 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08003846 // note that the value persisted is the current ringer mode, not the
3847 // value of ringer mode as of the time the request was made to persist
3848 persistRingerMode(getRingerMode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003849 break;
3850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003851 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07003852 if (!mSystemReady ||
3853 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07003854 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08003855 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07003856 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07003857 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07003858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07003860
Eric Laurent3c652ca2010-06-21 20:46:26 -07003861 // indicate to audio HAL that we start the reconfiguration phase after a media
3862 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07003863 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07003864 // process restarts after a crash, not the first time it is started.
3865 AudioSystem.setParameters("restarting=true");
3866
Glenn Kastenfd116ad2013-07-12 17:10:39 -07003867 readAndSetLowRamDevice();
3868
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003869 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003870 synchronized (mConnectedDevices) {
3871 Set set = mConnectedDevices.entrySet();
3872 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003873 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003874 Map.Entry device = (Map.Entry)i.next();
3875 AudioSystem.setDeviceConnectionState(
3876 ((Integer)device.getKey()).intValue(),
3877 AudioSystem.DEVICE_STATE_AVAILABLE,
3878 (String)device.getValue());
3879 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003880 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003881 // Restore call state
3882 AudioSystem.setPhoneState(mMode);
3883
Eric Laurentd5603c12009-08-06 08:49:39 -07003884 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003885 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07003886 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07003887 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3888 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003889
Eric Laurenta553c252009-07-17 12:17:14 -07003890 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003891 int numStreamTypes = AudioSystem.getNumStreamTypes();
3892 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003894 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003895
3896 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003897 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003898
3899 // Restore ringer mode
3900 setRingerModeInt(getRingerMode(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07003901
Mike Lockwood90631542012-01-06 11:20:37 -05003902 // Restore master volume
3903 restoreMasterVolume();
3904
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003905 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07003906 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003907 setOrientationForAudioSystem();
3908 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07003909 if (mMonitorRotation) {
3910 setRotationForAudioSystem();
3911 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003912
Eric Laurent78472112012-05-21 08:57:21 -07003913 synchronized (mBluetoothA2dpEnabledLock) {
3914 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3915 mBluetoothA2dpEnabled ?
3916 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3917 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07003918
3919 synchronized (mSettingsLock) {
3920 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3921 mDockAudioMediaEnabled ?
3922 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3923 }
Eric Laurent212532b2014-07-21 15:43:18 -07003924 if (mHdmiManager != null) {
3925 synchronized (mHdmiManager) {
3926 if (mHdmiTvClient != null) {
3927 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
3928 }
3929 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09003930 }
Eric Laurent3c652ca2010-06-21 20:46:26 -07003931 // indicate the end of reconfiguration phase to audio HAL
3932 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003933 break;
3934
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003935 case MSG_UNLOAD_SOUND_EFFECTS:
3936 onUnloadSoundEffects();
3937 break;
3938
Eric Laurent117b7bb2011-01-16 17:07:27 -08003939 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003940 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3941 // can take several dozens of milliseconds to complete
3942 boolean loaded = onLoadSoundEffects();
3943 if (msg.obj != null) {
3944 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3945 synchronized (reply) {
3946 reply.mStatus = loaded ? 0 : -1;
3947 reply.notify();
3948 }
3949 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08003950 break;
3951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003952 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003953 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003954 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003955
3956 case MSG_BTA2DP_DOCK_TIMEOUT:
3957 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003958 synchronized (mConnectedDevices) {
3959 makeA2dpDeviceUnavailableNow( (String) msg.obj );
3960 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003961 break;
Eric Laurentfa640152011-03-12 15:59:51 -08003962
3963 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07003964 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08003965 setForceUse(msg.arg1, msg.arg2);
3966 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07003967
Eric Laurentdc03c612011-04-01 10:59:41 -07003968 case MSG_BT_HEADSET_CNCT_FAILED:
3969 resetBluetoothSco();
3970 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003971
3972 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3973 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003974 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003975 break;
3976
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003977 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
3978 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3979 mAudioEventWakeLock.release();
3980 break;
3981
3982 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
3983 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003984 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003985 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07003986
3987 case MSG_REPORT_NEW_ROUTES: {
3988 int N = mRoutesObservers.beginBroadcast();
3989 if (N > 0) {
3990 AudioRoutesInfo routes;
3991 synchronized (mCurAudioRoutes) {
3992 routes = new AudioRoutesInfo(mCurAudioRoutes);
3993 }
3994 while (N > 0) {
3995 N--;
3996 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3997 try {
3998 obs.dispatchAudioRoutesChanged(routes);
3999 } catch (RemoteException e) {
4000 }
4001 }
4002 }
4003 mRoutesObservers.finishBroadcast();
4004 break;
4005 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004006
Eric Laurentc34dcc12012-09-10 13:51:52 -07004007 case MSG_CHECK_MUSIC_ACTIVE:
4008 onCheckMusicActive();
4009 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004010
4011 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4012 onSendBecomingNoisyIntent();
4013 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004014
4015 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4016 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4017 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4018 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004019 case MSG_PERSIST_SAFE_VOLUME_STATE:
4020 onPersistSafeVolumeState(msg.arg1);
4021 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004022
Eric Laurent2a57ca92013-03-07 17:29:27 -08004023 case MSG_BROADCAST_BT_CONNECTION_STATE:
4024 onBroadcastScoConnectionState(msg.arg1);
4025 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004026
4027 case MSG_SYSTEM_READY:
4028 onSystemReady();
4029 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004030
4031 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4032 final int musicActiveMs = msg.arg1;
4033 Settings.Secure.putIntForUser(mContentResolver,
4034 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4035 UserHandle.USER_CURRENT);
4036 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 }
4038 }
4039 }
4040
Jason Parekhb1096152009-03-24 17:48:25 -07004041 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004042
Jason Parekhb1096152009-03-24 17:48:25 -07004043 SettingsObserver() {
4044 super(new Handler());
4045 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4046 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004047 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4048 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004049 }
4050
4051 @Override
4052 public void onChange(boolean selfChange) {
4053 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004054 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4055 // However there appear to be some missing locks around mRingerModeMutedStreams
4056 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4057 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004058 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004059 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004060 /*
4061 * Ensure all stream types that should be affected by ringer mode
4062 * are in the proper state.
4063 */
Eric Laurenta553c252009-07-17 12:17:14 -07004064 setRingerModeInt(getRingerMode(), false);
4065 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004066 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004067 }
Jason Parekhb1096152009-03-24 17:48:25 -07004068 }
Jason Parekhb1096152009-03-24 17:48:25 -07004069 }
Eric Laurenta553c252009-07-17 12:17:14 -07004070
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004071 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004072 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004073 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4074 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004075 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4076 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4077 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004078 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004079 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4080 AudioSystem.DEVICE_STATE_AVAILABLE,
4081 address);
4082 // Reset A2DP suspend state each time a new sink is connected
4083 AudioSystem.setParameters("A2dpSuspended=false");
4084 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4085 address);
4086 }
4087
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004088 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004089 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004090 }
4091
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004092 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004093 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004094 synchronized (mA2dpAvrcpLock) {
4095 mAvrcpAbsVolSupported = false;
4096 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004097 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4098 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4099 address);
4100 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4101 }
4102
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004103 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004104 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004105 // prevent any activity on the A2DP audio output to avoid unwanted
4106 // reconnection of the sink.
4107 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004108 // the device will be made unavailable later, so consider it disconnected right away
4109 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4110 // send the delayed message to make the device unavailable later
4111 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4112 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4113
4114 }
4115
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004116 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004117 private void makeA2dpSrcAvailable(String address) {
4118 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4119 AudioSystem.DEVICE_STATE_AVAILABLE,
4120 address);
4121 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4122 address);
4123 }
4124
4125 // must be called synchronized on mConnectedDevices
4126 private void makeA2dpSrcUnavailable(String address) {
4127 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4128 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4129 address);
4130 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4131 }
4132
4133 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004134 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004135 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4136 }
4137
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004138 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004139 private boolean hasScheduledA2dpDockTimeout() {
4140 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4141 }
4142
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004143 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004144 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004145 if (DEBUG_VOL) {
4146 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4147 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004148 if (btDevice == null) {
4149 return;
4150 }
4151 String address = btDevice.getAddress();
4152 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4153 address = "";
4154 }
John Du5a0cf7a2013-07-19 11:30:34 -07004155
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004156 synchronized (mConnectedDevices) {
4157 boolean isConnected =
4158 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4159 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4160
4161 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4162 if (btDevice.isBluetoothDock()) {
4163 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4164 // introduction of a delay for transient disconnections of docks when
4165 // power is rapidly turned off/on, this message will be canceled if
4166 // we reconnect the dock under a preset delay
4167 makeA2dpDeviceUnavailableLater(address);
4168 // the next time isConnected is evaluated, it will be false for the dock
4169 }
4170 } else {
4171 makeA2dpDeviceUnavailableNow(address);
4172 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004173 synchronized (mCurAudioRoutes) {
4174 if (mCurAudioRoutes.mBluetoothName != null) {
4175 mCurAudioRoutes.mBluetoothName = null;
4176 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4177 SENDMSG_NOOP, 0, 0, null, 0);
4178 }
4179 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004180 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4181 if (btDevice.isBluetoothDock()) {
4182 // this could be a reconnection after a transient disconnection
4183 cancelA2dpDeviceTimeout();
4184 mDockAddress = address;
4185 } else {
4186 // this could be a connection of another A2DP device before the timeout of
4187 // a dock: cancel the dock timeout, and make the dock unavailable now
4188 if(hasScheduledA2dpDockTimeout()) {
4189 cancelA2dpDeviceTimeout();
4190 makeA2dpDeviceUnavailableNow(mDockAddress);
4191 }
4192 }
4193 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004194 synchronized (mCurAudioRoutes) {
4195 String name = btDevice.getAliasName();
4196 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4197 mCurAudioRoutes.mBluetoothName = name;
4198 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4199 SENDMSG_NOOP, 0, 0, null, 0);
4200 }
4201 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004202 }
4203 }
4204 }
4205
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004206 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4207 {
4208 if (DEBUG_VOL) {
4209 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4210 }
4211 if (btDevice == null) {
4212 return;
4213 }
4214 String address = btDevice.getAddress();
4215 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4216 address = "";
4217 }
4218
4219 synchronized (mConnectedDevices) {
4220 boolean isConnected =
4221 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4222 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4223
4224 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4225 makeA2dpSrcUnavailable(address);
4226 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4227 makeA2dpSrcAvailable(address);
4228 }
4229 }
4230 }
4231
John Du5a0cf7a2013-07-19 11:30:34 -07004232 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4233 // address is not used for now, but may be used when multiple a2dp devices are supported
4234 synchronized (mA2dpAvrcpLock) {
4235 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004236 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004237 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4238 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4239 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4240 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4241 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004242 }
4243 }
4244
Eric Laurent59f48272012-04-05 19:42:21 -07004245 private boolean handleDeviceConnection(boolean connected, int device, String params) {
4246 synchronized (mConnectedDevices) {
4247 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Mike Lockwood98418182012-05-10 17:13:20 -07004248 (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
Eric Laurent59f48272012-04-05 19:42:21 -07004249
4250 if (isConnected && !connected) {
4251 AudioSystem.setDeviceConnectionState(device,
4252 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Mike Lockwood98418182012-05-10 17:13:20 -07004253 mConnectedDevices.get(device));
Eric Laurent59f48272012-04-05 19:42:21 -07004254 mConnectedDevices.remove(device);
4255 return true;
4256 } else if (!isConnected && connected) {
4257 AudioSystem.setDeviceConnectionState(device,
4258 AudioSystem.DEVICE_STATE_AVAILABLE,
4259 params);
4260 mConnectedDevices.put(new Integer(device), params);
4261 return true;
4262 }
4263 }
4264 return false;
4265 }
4266
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004267 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4268 // sent if none of these devices is connected.
4269 int mBecomingNoisyIntentDevices =
4270 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004271 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004272 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004273 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004274
4275 // must be called before removing the device from mConnectedDevices
4276 private int checkSendBecomingNoisyIntent(int device, int state) {
4277 int delay = 0;
4278 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4279 int devices = 0;
4280 for (int dev : mConnectedDevices.keySet()) {
4281 if ((dev & mBecomingNoisyIntentDevices) != 0) {
4282 devices |= dev;
4283 }
4284 }
4285 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004286 sendMsg(mAudioHandler,
4287 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4288 SENDMSG_REPLACE,
4289 0,
4290 0,
4291 null,
4292 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004293 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004294 }
4295 }
4296
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004297 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4298 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004299 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4300 delay = 1000;
4301 }
4302 return delay;
4303 }
4304
4305 private void sendDeviceConnectionIntent(int device, int state, String name)
4306 {
4307 Intent intent = new Intent();
4308
4309 intent.putExtra("state", state);
4310 intent.putExtra("name", name);
4311 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4312
Dianne Hackborn632ca412012-06-14 19:34:10 -07004313 int connType = 0;
4314
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004315 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004316 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004317 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4318 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004319 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4320 device == AudioSystem.DEVICE_OUT_LINE) {
4321 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004322 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004323 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4324 intent.putExtra("microphone", 0);
4325 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004326 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004327 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4328 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004329 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004330 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
Eric Laurent948d3272014-05-16 15:18:45 -07004331 } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004332 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004333 configureHdmiPlugIntent(intent, state);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004334 }
4335
Dianne Hackborn632ca412012-06-14 19:34:10 -07004336 synchronized (mCurAudioRoutes) {
4337 if (connType != 0) {
4338 int newConn = mCurAudioRoutes.mMainType;
4339 if (state != 0) {
4340 newConn |= connType;
4341 } else {
4342 newConn &= ~connType;
4343 }
4344 if (newConn != mCurAudioRoutes.mMainType) {
4345 mCurAudioRoutes.mMainType = newConn;
4346 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4347 SENDMSG_NOOP, 0, 0, null, 0);
4348 }
4349 }
4350 }
4351
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004352 final long ident = Binder.clearCallingIdentity();
4353 try {
4354 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4355 } finally {
4356 Binder.restoreCallingIdentity(ident);
4357 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004358 }
4359
4360 private void onSetWiredDeviceConnectionState(int device, int state, String name)
4361 {
4362 synchronized (mConnectedDevices) {
4363 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004364 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4365 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004366 setBluetoothA2dpOnInt(true);
4367 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004368 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4369 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4370 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Mike Lockwooddb454842012-09-18 11:16:57 -07004371 handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
Eric Laurentf1a457d2012-09-20 16:27:23 -07004372 if (state != 0) {
4373 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004374 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4375 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004376 setBluetoothA2dpOnInt(false);
4377 }
4378 if ((device & mSafeMediaVolumeDevices) != 0) {
4379 sendMsg(mAudioHandler,
4380 MSG_CHECK_MUSIC_ACTIVE,
4381 SENDMSG_REPLACE,
4382 0,
4383 0,
4384 null,
4385 MUSIC_ACTIVE_POLL_PERIOD_MS);
4386 }
Eric Laurent212532b2014-07-21 15:43:18 -07004387 // Television devices without CEC service apply software volume on HDMI output
4388 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4389 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4390 checkAllFixedVolumeDevices();
4391 if (mHdmiManager != null) {
4392 synchronized (mHdmiManager) {
4393 if (mHdmiPlaybackClient != null) {
4394 mHdmiCecSink = false;
4395 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4396 }
4397 }
4398 }
4399 }
4400 } else {
4401 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4402 if (mHdmiManager != null) {
4403 synchronized (mHdmiManager) {
4404 mHdmiCecSink = false;
4405 }
4406 }
4407 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004408 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004409 if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
Mike Lockwooddb454842012-09-18 11:16:57 -07004410 sendDeviceConnectionIntent(device, state, name);
4411 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004412 }
4413 }
4414
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004415 private void configureHdmiPlugIntent(Intent intent, int state) {
4416 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4417 if (state == 1) {
4418 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4419 int[] portGeneration = new int[1];
4420 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4421 if (status == AudioManager.SUCCESS) {
4422 for (AudioPort port : ports) {
4423 if (port instanceof AudioDevicePort) {
4424 final AudioDevicePort devicePort = (AudioDevicePort) port;
4425 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI) {
4426 // format the list of supported encodings
4427 int[] formats = devicePort.formats();
4428 if (formats.length > 0) {
4429 ArrayList<Integer> encodingList = new ArrayList(1);
4430 for (int format : formats) {
4431 // a format in the list can be 0, skip it
4432 if (format != AudioFormat.ENCODING_INVALID) {
4433 encodingList.add(format);
4434 }
4435 }
4436 int[] encodingArray = new int[encodingList.size()];
4437 for (int i = 0 ; i < encodingArray.length ; i++) {
4438 encodingArray[i] = encodingList.get(i);
4439 }
4440 intent.putExtra("encodings", encodingArray);
4441 }
4442 // find the maximum supported number of channels
4443 int maxChannels = 0;
4444 for (int mask : devicePort.channelMasks()) {
4445 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4446 if (channelCount > maxChannels) {
4447 maxChannels = channelCount;
4448 }
4449 }
4450 intent.putExtra("maxChannelCount", maxChannels);
4451 }
4452 }
4453 }
4454 }
4455 }
4456 }
4457
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004458 /* cache of the address of the last dock the device was connected to */
4459 private String mDockAddress;
4460
Eric Laurenta553c252009-07-17 12:17:14 -07004461 /**
4462 * Receiver for misc intent broadcasts the Phone app cares about.
4463 */
4464 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4465 @Override
4466 public void onReceive(Context context, Intent intent) {
4467 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004468 int outDevice;
4469 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004470 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004471
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004472 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4473 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4474 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4475 int config;
4476 switch (dockState) {
4477 case Intent.EXTRA_DOCK_STATE_DESK:
4478 config = AudioSystem.FORCE_BT_DESK_DOCK;
4479 break;
4480 case Intent.EXTRA_DOCK_STATE_CAR:
4481 config = AudioSystem.FORCE_BT_CAR_DOCK;
4482 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004483 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004484 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004485 break;
4486 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4487 config = AudioSystem.FORCE_DIGITAL_DOCK;
4488 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004489 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4490 default:
4491 config = AudioSystem.FORCE_NONE;
4492 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004493 // Low end docks have a menu to enable or disable audio
4494 // (see mDockAudioMediaEnabled)
4495 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4496 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4497 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4498 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4499 }
4500 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004501 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004502 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004503 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004504 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4505 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004506 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004507
4508 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4509 if (btDevice == null) {
4510 return;
4511 }
4512
4513 address = btDevice.getAddress();
4514 BluetoothClass btClass = btDevice.getBluetoothClass();
4515 if (btClass != null) {
4516 switch (btClass.getDeviceClass()) {
4517 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4518 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004519 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004520 break;
4521 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004522 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004523 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004524 }
4525 }
4526
Eric Laurentdca56b92011-09-02 14:20:56 -07004527 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4528 address = "";
4529 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004530
Eric Laurent59f48272012-04-05 19:42:21 -07004531 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004532 boolean success = handleDeviceConnection(connected, outDevice, address) &&
4533 handleDeviceConnection(connected, inDevice, address);
4534 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004535 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004536 if (connected) {
4537 mBluetoothHeadsetDevice = btDevice;
4538 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004539 mBluetoothHeadsetDevice = null;
4540 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004541 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004542 }
Eric Laurenta553c252009-07-17 12:17:14 -07004543 }
Paul McLeandf361462014-04-10 16:02:55 -07004544 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4545 state = intent.getIntExtra("state", 0);
4546
4547 int alsaCard = intent.getIntExtra("card", -1);
4548 int alsaDevice = intent.getIntExtra("device", -1);
4549
4550 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4551 : "card=" + alsaCard + ";device=" + alsaDevice);
4552
4553 // Playback Device
Eric Laurentae4506e2014-05-29 16:04:32 -07004554 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4555 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004556 } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
Glenn Kasten5f516352014-07-22 09:11:48 -07004557 // FIXME Does not yet handle the case where the setting is changed
4558 // after device connection. Ideally we should handle the settings change
4559 // in SettingsObserver. Here we should log that a USB device is connected
4560 // and disconnected with its address (card , device) and force the
4561 // connection or disconnection when the setting changes.
Glenn Kasten34cc4db2014-08-13 10:56:38 -07004562 int isDisabled = Settings.Secure.getInt(mContentResolver,
4563 Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
Glenn Kasten5f516352014-07-22 09:11:48 -07004564 if (isDisabled != 0) {
4565 return;
4566 }
4567
Eric Laurent59f48272012-04-05 19:42:21 -07004568 state = intent.getIntExtra("state", 0);
Paul McLeanc837a452014-04-09 09:04:43 -07004569
Eric Laurent59f48272012-04-05 19:42:21 -07004570 int alsaCard = intent.getIntExtra("card", -1);
4571 int alsaDevice = intent.getIntExtra("device", -1);
Paul McLeanc837a452014-04-09 09:04:43 -07004572 boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4573 boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4574 boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4575
Mike Lockwood98418182012-05-10 17:13:20 -07004576 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4577 : "card=" + alsaCard + ";device=" + alsaDevice);
Paul McLeanc837a452014-04-09 09:04:43 -07004578
Paul McLeanc837a452014-04-09 09:04:43 -07004579 // Playback Device
Paul McLeandf361462014-04-10 16:02:55 -07004580 if (hasPlayback) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004581 outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4582 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004583 }
Paul McLeanc837a452014-04-09 09:04:43 -07004584
4585 // Capture Device
Paul McLeandf361462014-04-10 16:02:55 -07004586 if (hasCapture) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004587 inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4588 setWiredDeviceConnectionState(inDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004589 }
4590 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004591 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004592 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004593 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004594 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004595 // broadcast intent if the connection was initated by AudioService
4596 if (!mScoClients.isEmpty() &&
4597 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4598 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4599 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004600 broadcast = true;
4601 }
4602 switch (btState) {
4603 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004604 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004605 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4606 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4607 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004608 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004609 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004610 break;
4611 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004612 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004613 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004614 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004615 break;
4616 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004617 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4618 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4619 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004620 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004621 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004622 default:
4623 // do not broadcast CONNECTING or invalid state
4624 broadcast = false;
4625 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004626 }
4627 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004628 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004629 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004630 //FIXME: this is to maintain compatibility with deprecated intent
4631 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004632 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004633 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004634 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004635 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004636 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4637 AudioSystem.setParameters("screen_state=on");
4638 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4639 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004640 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004641 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004642 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004643 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004644 sendMsg(mAudioHandler,
4645 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4646 SENDMSG_REPLACE,
4647 0,
4648 0,
4649 null,
4650 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004651 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004652 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004653
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004654 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004655 readAudioSettings(true /*userSwitch*/);
4656 // preserve STREAM_MUSIC volume from one user to the next.
4657 sendMsg(mAudioHandler,
4658 MSG_SET_ALL_VOLUMES,
4659 SENDMSG_QUEUE,
4660 0,
4661 0,
4662 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004663 }
4664 }
Paul McLeanc837a452014-04-09 09:04:43 -07004665 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004666
4667 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004668 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004669 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004670 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4671 ComponentName listenerComp) {
4672 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4673 }
4674
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004675 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004676 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004677 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004678
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004679 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004680 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004681 }
4682
4683 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004684 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004685 }
4686
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004687 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4688 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004689 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4690 }
4691
John Spurlock3346a802014-05-20 16:25:37 -04004692 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004693 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04004694 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004695 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004696 }
4697
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004698 //==========================================================================================
4699 // Audio Focus
4700 //==========================================================================================
4701 public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4702 IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4703 return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4704 clientId, callingPackageName);
4705 }
4706
4707 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4708 return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4709 }
4710
4711 public void unregisterAudioFocusClient(String clientId) {
4712 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004713 }
4714
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004715 public int getCurrentAudioFocus() {
4716 return mMediaFocusControl.getCurrentAudioFocus();
4717 }
4718
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004719 //==========================================================================================
4720 // Device orientation
4721 //==========================================================================================
4722 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004723 * Handles device configuration changes that may map to a change in the orientation
4724 * or orientation.
4725 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4726 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004727 */
4728 private void handleConfigurationChanged(Context context) {
4729 try {
4730 // reading new orientation "safely" (i.e. under try catch) in case anything
4731 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004732 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004733 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004734 if (mMonitorOrientation) {
4735 int newOrientation = config.orientation;
4736 if (newOrientation != mDeviceOrientation) {
4737 mDeviceOrientation = newOrientation;
4738 setOrientationForAudioSystem();
4739 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004740 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004741 if (mMonitorRotation) {
4742 int newRotation = ((WindowManager) context.getSystemService(
4743 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4744 if (newRotation != mDeviceRotation) {
4745 mDeviceRotation = newRotation;
4746 setRotationForAudioSystem();
4747 }
4748 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004749 sendMsg(mAudioHandler,
4750 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4751 SENDMSG_REPLACE,
4752 0,
4753 0,
4754 null,
4755 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004756
4757 boolean cameraSoundForced = mContext.getResources().getBoolean(
4758 com.android.internal.R.bool.config_camera_sound_forced);
4759 synchronized (mSettingsLock) {
4760 synchronized (mCameraSoundForced) {
4761 if (cameraSoundForced != mCameraSoundForced) {
4762 mCameraSoundForced = cameraSoundForced;
4763
Eric Laurent212532b2014-07-21 15:43:18 -07004764 if (!isPlatformTelevision()) {
4765 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4766 if (cameraSoundForced) {
4767 s.setAllIndexesToMax();
4768 mRingerModeAffectedStreams &=
4769 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4770 } else {
4771 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4772 mRingerModeAffectedStreams |=
4773 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4774 }
4775 // take new state into account for streams muted by ringer mode
4776 setRingerModeInt(getRingerMode(), false);
Eric Laurentdd45d012012-10-08 09:04:34 -07004777 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004778
4779 sendMsg(mAudioHandler,
4780 MSG_SET_FORCE_USE,
4781 SENDMSG_QUEUE,
4782 AudioSystem.FOR_SYSTEM,
4783 cameraSoundForced ?
4784 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4785 null,
4786 0);
4787
4788 sendMsg(mAudioHandler,
4789 MSG_SET_ALL_VOLUMES,
4790 SENDMSG_QUEUE,
4791 0,
4792 0,
4793 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4794 }
4795 }
4796 }
John Spurlock3346a802014-05-20 16:25:37 -04004797 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004798 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004799 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004800 }
4801 }
4802
4803 private void setOrientationForAudioSystem() {
4804 switch (mDeviceOrientation) {
4805 case Configuration.ORIENTATION_LANDSCAPE:
4806 //Log.i(TAG, "orientation is landscape");
4807 AudioSystem.setParameters("orientation=landscape");
4808 break;
4809 case Configuration.ORIENTATION_PORTRAIT:
4810 //Log.i(TAG, "orientation is portrait");
4811 AudioSystem.setParameters("orientation=portrait");
4812 break;
4813 case Configuration.ORIENTATION_SQUARE:
4814 //Log.i(TAG, "orientation is square");
4815 AudioSystem.setParameters("orientation=square");
4816 break;
4817 case Configuration.ORIENTATION_UNDEFINED:
4818 //Log.i(TAG, "orientation is undefined");
4819 AudioSystem.setParameters("orientation=undefined");
4820 break;
4821 default:
4822 Log.e(TAG, "Unknown orientation");
4823 }
4824 }
4825
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004826 private void setRotationForAudioSystem() {
4827 switch (mDeviceRotation) {
4828 case Surface.ROTATION_0:
4829 AudioSystem.setParameters("rotation=0");
4830 break;
4831 case Surface.ROTATION_90:
4832 AudioSystem.setParameters("rotation=90");
4833 break;
4834 case Surface.ROTATION_180:
4835 AudioSystem.setParameters("rotation=180");
4836 break;
4837 case Surface.ROTATION_270:
4838 AudioSystem.setParameters("rotation=270");
4839 break;
4840 default:
4841 Log.e(TAG, "Unknown device rotation");
4842 }
4843 }
4844
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004845
Eric Laurent78472112012-05-21 08:57:21 -07004846 // Handles request to override default use of A2DP for media.
4847 public void setBluetoothA2dpOnInt(boolean on) {
4848 synchronized (mBluetoothA2dpEnabledLock) {
4849 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07004850 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4851 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4852 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07004853 }
4854 }
4855
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004856 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07004857 public void setRingtonePlayer(IRingtonePlayer player) {
4858 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4859 mRingtonePlayer = player;
4860 }
4861
4862 @Override
4863 public IRingtonePlayer getRingtonePlayer() {
4864 return mRingtonePlayer;
4865 }
4866
4867 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07004868 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4869 synchronized (mCurAudioRoutes) {
4870 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4871 mRoutesObservers.register(observer);
4872 return routes;
4873 }
4874 }
4875
Eric Laurentc34dcc12012-09-10 13:51:52 -07004876
4877 //==========================================================================================
4878 // Safe media volume management.
4879 // MUSIC stream volume level is limited when headphones are connected according to safety
4880 // regulation. When the user attempts to raise the volume above the limit, a warning is
4881 // displayed and the user has to acknowlegde before the volume is actually changed.
4882 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4883 // property. Platforms with a different limit must set this property accordingly in their
4884 // overlay.
4885 //==========================================================================================
4886
Eric Laurentd640bd32012-09-28 18:01:48 -07004887 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4888 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4889 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4890 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4891 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4892 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04004893 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4894 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4895 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
4896 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07004897 private Integer mSafeMediaVolumeState;
4898
4899 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004900 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07004901 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004902 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4903 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4904 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4905 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4906 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4907 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4908 private int mMusicActiveMs;
4909 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4910 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07004911 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07004912
4913 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004914 synchronized (mSafeMediaVolumeState) {
4915 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4916 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4917 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4918 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4919 enforceSafeMediaVolume();
4920 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4921 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004922 mMusicActiveMs = 1; // nonzero = confirmed
4923 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07004924 sendMsg(mAudioHandler,
4925 MSG_CHECK_MUSIC_ACTIVE,
4926 SENDMSG_REPLACE,
4927 0,
4928 0,
4929 null,
4930 MUSIC_ACTIVE_POLL_PERIOD_MS);
4931 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004932 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004933 }
4934 }
4935
4936 private void enforceSafeMediaVolume() {
4937 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07004938 int devices = mSafeMediaVolumeDevices;
4939 int i = 0;
4940
4941 while (devices != 0) {
4942 int device = 1 << i++;
4943 if ((device & devices) == 0) {
4944 continue;
4945 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004946 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004947 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004948 streamState.setIndex(mSafeMediaVolumeIndex, device);
4949 sendMsg(mAudioHandler,
4950 MSG_SET_DEVICE_VOLUME,
4951 SENDMSG_QUEUE,
4952 device,
4953 0,
4954 streamState,
4955 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004956 }
4957 devices &= ~device;
4958 }
4959 }
4960
4961 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004962 synchronized (mSafeMediaVolumeState) {
4963 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07004964 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4965 ((device & mSafeMediaVolumeDevices) != 0) &&
4966 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004967 return false;
4968 }
4969 return true;
4970 }
4971 }
4972
John Spurlock3346a802014-05-20 16:25:37 -04004973 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07004974 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04004975 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07004976 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004977 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08004978 if (mPendingVolumeCommand != null) {
4979 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4980 mPendingVolumeCommand.mIndex,
4981 mPendingVolumeCommand.mFlags,
4982 mPendingVolumeCommand.mDevice);
4983 mPendingVolumeCommand = null;
4984 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004985 }
4986 }
4987
Jungshik Jang41d97462014-06-30 22:26:29 +09004988 //==========================================================================================
4989 // Hdmi Cec system audio mode.
4990 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
4991 // to HdmiControlService so that audio recevier can handle volume change.
4992 //==========================================================================================
4993
Eric Laurent212532b2014-07-21 15:43:18 -07004994 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
4995 public void onComplete(int status) {
4996 if (mHdmiManager != null) {
4997 synchronized (mHdmiManager) {
4998 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
4999 // Television devices without CEC service apply software volume on HDMI output
5000 if (isPlatformTelevision() && !mHdmiCecSink) {
5001 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5002 }
5003 checkAllFixedVolumeDevices();
5004 }
5005 }
5006 }
5007 };
5008
Jungshik Jang41d97462014-06-30 22:26:29 +09005009 // If HDMI-CEC system audio is supported
5010 private boolean mHdmiSystemAudioSupported = false;
5011 // Set only when device is tv.
5012 private HdmiTvClient mHdmiTvClient;
Eric Laurent212532b2014-07-21 15:43:18 -07005013 // true if the device has system feature PackageManager.FEATURE_TELEVISION.
5014 // cached HdmiControlManager interface
5015 private HdmiControlManager mHdmiManager;
5016 // Set only when device is a set-top box.
5017 private HdmiPlaybackClient mHdmiPlaybackClient;
5018 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5019 private boolean mHdmiCecSink;
5020
5021 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005022
5023 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005024 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005025 int device = AudioSystem.DEVICE_NONE;
5026 if (mHdmiManager != null) {
5027 synchronized (mHdmiManager) {
5028 if (mHdmiTvClient == null) {
5029 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5030 return device;
5031 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005032
Eric Laurent212532b2014-07-21 15:43:18 -07005033 synchronized (mHdmiTvClient) {
5034 if (mHdmiSystemAudioSupported != on) {
5035 mHdmiSystemAudioSupported = on;
5036 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5037 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5038 AudioSystem.FORCE_NONE);
5039 }
5040 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5041 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005042 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005043 }
Eric Laurent212532b2014-07-21 15:43:18 -07005044 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005045 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005046
Eric Laurentdd45d012012-10-08 09:04:34 -07005047 //==========================================================================================
5048 // Camera shutter sound policy.
5049 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5050 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5051 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5052 //==========================================================================================
5053
5054 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5055 private Boolean mCameraSoundForced;
5056
5057 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5058 public boolean isCameraSoundForced() {
5059 synchronized (mCameraSoundForced) {
5060 return mCameraSoundForced;
5061 }
5062 }
5063
5064 private static final String[] RINGER_MODE_NAMES = new String[] {
5065 "SILENT",
5066 "VIBRATE",
5067 "NORMAL"
5068 };
5069
5070 private void dumpRingerMode(PrintWriter pw) {
5071 pw.println("\nRinger mode: ");
5072 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
5073 pw.print("- ringer mode affected streams = 0x");
5074 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5075 pw.print("- ringer mode muted streams = 0x");
5076 pw.println(Integer.toHexString(mRingerModeMutedStreams));
5077 }
5078
Dianne Hackborn632ca412012-06-14 19:34:10 -07005079 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005080 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005081 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5082
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005083 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005084 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005085 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005086 pw.println("\nAudio routes:");
5087 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5088 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005089
5090 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005091 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005092 pw.print(" mSafeMediaVolumeState=");
5093 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5094 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5095 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5096 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005097 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock35134602014-07-24 18:10:48 -04005098 }
5099
5100 private static String safeMediaVolumeStateToString(Integer state) {
5101 switch(state) {
5102 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5103 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5104 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5105 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5106 }
5107 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005108 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005109
5110 // Inform AudioFlinger of our device's low RAM attribute
5111 private static void readAndSetLowRamDevice()
5112 {
5113 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5114 if (status != 0) {
5115 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5116 }
5117 }
John Spurlock3346a802014-05-20 16:25:37 -04005118
5119 private void enforceSelfOrSystemUI(String action) {
5120 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5121 "Only SystemUI can " + action);
5122 }
5123
5124 @Override
5125 public void setVolumeController(final IVolumeController controller) {
5126 enforceSelfOrSystemUI("set the volume controller");
5127
5128 // return early if things are not actually changing
5129 if (mVolumeController.isSameBinder(controller)) {
5130 return;
5131 }
5132
5133 // dismiss the old volume controller
5134 mVolumeController.postDismiss();
5135 if (controller != null) {
5136 // we are about to register a new controller, listen for its death
5137 try {
5138 controller.asBinder().linkToDeath(new DeathRecipient() {
5139 @Override
5140 public void binderDied() {
5141 if (mVolumeController.isSameBinder(controller)) {
5142 Log.w(TAG, "Current remote volume controller died, unregistering");
5143 setVolumeController(null);
5144 }
5145 }
5146 }, 0);
5147 } catch (RemoteException e) {
5148 // noop
5149 }
5150 }
5151 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005152 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5153 }
5154
5155 @Override
5156 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5157 enforceSelfOrSystemUI("notify about volume controller visibility");
5158
5159 // return early if the controller is not current
5160 if (!mVolumeController.isSameBinder(controller)) {
5161 return;
5162 }
5163
5164 mVolumeController.setVisible(visible);
5165 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005166 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005167
5168 public static class VolumeController {
5169 private static final String TAG = "VolumeController";
5170
5171 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005172 private boolean mVisible;
5173 private long mNextLongPress;
5174 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005175
5176 public void setController(IVolumeController controller) {
5177 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005178 mVisible = false;
5179 }
5180
5181 public void loadSettings(ContentResolver cr) {
5182 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5183 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5184 }
5185
5186 public boolean suppressAdjustment(int resolvedStream, int flags) {
5187 boolean suppress = false;
5188 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5189 final long now = SystemClock.uptimeMillis();
5190 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5191 // ui will become visible
5192 if (mNextLongPress < now) {
5193 mNextLongPress = now + mLongPressTimeout;
5194 }
5195 suppress = true;
5196 } else if (mNextLongPress > 0) { // in a long-press
5197 if (now > mNextLongPress) {
5198 // long press triggered, no more suppression
5199 mNextLongPress = 0;
5200 } else {
5201 // keep suppressing until the long press triggers
5202 suppress = true;
5203 }
5204 }
5205 }
5206 return suppress;
5207 }
5208
5209 public void setVisible(boolean visible) {
5210 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005211 }
5212
5213 public boolean isSameBinder(IVolumeController controller) {
5214 return Objects.equals(asBinder(), binder(controller));
5215 }
5216
5217 public IBinder asBinder() {
5218 return binder(mController);
5219 }
5220
5221 private static IBinder binder(IVolumeController controller) {
5222 return controller == null ? null : controller.asBinder();
5223 }
5224
5225 @Override
5226 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005227 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005228 }
5229
5230 public void postDisplaySafeVolumeWarning(int flags) {
5231 if (mController == null)
5232 return;
5233 try {
5234 mController.displaySafeVolumeWarning(flags);
5235 } catch (RemoteException e) {
5236 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5237 }
5238 }
5239
5240 public void postVolumeChanged(int streamType, int flags) {
5241 if (mController == null)
5242 return;
5243 try {
5244 mController.volumeChanged(streamType, flags);
5245 } catch (RemoteException e) {
5246 Log.w(TAG, "Error calling volumeChanged", e);
5247 }
5248 }
5249
5250 public void postMasterVolumeChanged(int flags) {
5251 if (mController == null)
5252 return;
5253 try {
5254 mController.masterVolumeChanged(flags);
5255 } catch (RemoteException e) {
5256 Log.w(TAG, "Error calling masterVolumeChanged", e);
5257 }
5258 }
5259
5260 public void postMasterMuteChanged(int flags) {
5261 if (mController == null)
5262 return;
5263 try {
5264 mController.masterMuteChanged(flags);
5265 } catch (RemoteException e) {
5266 Log.w(TAG, "Error calling masterMuteChanged", e);
5267 }
5268 }
5269
5270 public void setLayoutDirection(int layoutDirection) {
5271 if (mController == null)
5272 return;
5273 try {
5274 mController.setLayoutDirection(layoutDirection);
5275 } catch (RemoteException e) {
5276 Log.w(TAG, "Error calling setLayoutDirection", e);
5277 }
5278 }
5279
5280 public void postDismiss() {
5281 if (mController == null)
5282 return;
5283 try {
5284 mController.dismiss();
5285 } catch (RemoteException e) {
5286 Log.w(TAG, "Error calling dismiss", e);
5287 }
5288 }
5289 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005290
5291 //==========================================================================================
5292 // Audio policy management
5293 //==========================================================================================
5294 public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
5295 //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
5296 boolean hasPermissionForPolicy =
5297 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
5298 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5299 if (!hasPermissionForPolicy) {
5300 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5301 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5302 return false;
5303 }
5304 synchronized (mAudioPolicies) {
5305 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
5306 try {
5307 cb.linkToDeath(app, 0/*flags*/);
5308 mAudioPolicies.put(cb, app);
5309 } catch (RemoteException e) {
5310 // audio policy owner has already died!
5311 Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
5312 " binder death", e);
5313 return false;
5314 }
5315 }
5316 // TODO implement registration with native audio policy (including permission check)
5317 return true;
5318 }
5319 public void unregisterAudioPolicyAsync(IBinder cb) {
5320 synchronized (mAudioPolicies) {
5321 AudioPolicyProxy app = mAudioPolicies.remove(cb);
5322 if (app == null) {
5323 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5324 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5325 } else {
5326 cb.unlinkToDeath(app, 0/*flags*/);
5327 }
5328 }
5329 // TODO implement registration with native audio policy
5330 }
5331
5332 public class AudioPolicyProxy implements IBinder.DeathRecipient {
5333 private static final String TAG = "AudioPolicyProxy";
5334 AudioPolicyConfig mConfig;
5335 IBinder mToken;
5336 AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
5337 mConfig = config;
5338 mToken = token;
5339 }
5340
5341 public void binderDied() {
5342 synchronized (mAudioPolicies) {
5343 Log.v(TAG, "audio policy " + mToken + " died");
5344 mAudioPolicies.remove(mToken);
5345 }
5346 }
5347 };
5348
5349 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5350 new HashMap<IBinder, AudioPolicyProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005351}