blob: 3fea68896fbfc4ec09bec7a1de894fdc59d1a57f [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;
RoboErik0dac35a2014-08-12 15:48:49 -070082import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -070083
84import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080086import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080088import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -070089import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import java.util.ArrayList;
Eric Laurent3172d5e2012-05-09 11:38:16 -070091import java.util.concurrent.ConcurrentHashMap;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +090092import java.util.Arrays;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070093import java.util.HashMap;
94import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070095import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070096import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070097import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -070098import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070099import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
101/**
102 * The implementation of the volume manager service.
103 * <p>
104 * This implementation focuses on delivering a responsive UI. Most methods are
105 * asynchronous to external calls. For example, the task of setting a volume
106 * will update our internal state, but in a separate thread will set the system
107 * volume and later persist to the database. Similarly, setting the ringer mode
108 * will update the state and broadcast a change and in a separate thread later
109 * persist the ringer mode.
110 *
111 * @hide
112 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700113public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
115 private static final String TAG = "AudioService";
116
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700117 /** Debug audio mode */
118 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700119 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400120 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700121
RoboErik430fc482014-06-12 15:49:20 -0700122 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400123 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700124
John Spurlock86005342014-05-23 11:58:00 -0400125 /** Allow volume changes to set ringer mode to silent? */
126 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
127
John Spurlocka11b4af2014-06-01 11:52:23 -0400128 /** In silent mode, are volume adjustments (raises) prevented? */
129 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700132 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
John Spurlock3346a802014-05-20 16:25:37 -0400134 /**
135 * The delay before playing a sound. This small period exists so the user
136 * can press another key (non-volume keys, too) to have it NOT be audible.
137 * <p>
138 * PhoneWindow will implement this part.
139 */
140 public static final int PLAY_SOUND_DELAY = 300;
141
John Spurlocka11b4af2014-06-01 11:52:23 -0400142 /**
143 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
144 */
145 private static final int FLAG_ADJUST_VOLUME = 1;
146
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700147 private final Context mContext;
148 private final ContentResolver mContentResolver;
149 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700150
151 // the platform has no specific capabilities
152 private static final int PLATFORM_DEFAULT = 0;
153 // the platform is voice call capable (a phone)
154 private static final int PLATFORM_VOICE = 1;
155 // the platform is a television or a set-top box
156 private static final int PLATFORM_TELEVISION = 2;
157 // the platform type affects volume and silent mode behavior
158 private final int mPlatformType;
159
160 private boolean isPlatformVoice() {
161 return mPlatformType == PLATFORM_VOICE;
162 }
163
164 private boolean isPlatformTelevision() {
165 return mPlatformType == PLATFORM_TELEVISION;
166 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800167
John Spurlock3346a802014-05-20 16:25:37 -0400168 /** The controller for the volume UI. */
169 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
171 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /** If the msg is already queued, replace it with this one. */
173 private static final int SENDMSG_REPLACE = 0;
174 /** If the msg is already queued, ignore this one and leave the old. */
175 private static final int SENDMSG_NOOP = 1;
176 /** If the msg is already queued, queue this one and leave the old. */
177 private static final int SENDMSG_QUEUE = 2;
178
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700179 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800180 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500182 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700184 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700185 private static final int MSG_PLAY_SOUND_EFFECT = 5;
186 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
187 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
188 private static final int MSG_SET_FORCE_USE = 8;
189 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
190 private static final int MSG_SET_ALL_VOLUMES = 10;
191 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
192 private static final int MSG_REPORT_NEW_ROUTES = 12;
193 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
194 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
195 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
196 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
197 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
198 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
199 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
200 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700201 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400202 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700203 // start of messages handled under wakelock
204 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700205 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700206 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700207 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
208 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700209 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800210
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700211 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700212 // Timeout for connection to bluetooth headset service
213 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 /** @see AudioSystemThread */
216 private AudioSystemThread mAudioSystemThread;
217 /** @see AudioHandler */
218 private AudioHandler mAudioHandler;
219 /** @see VolumeStreamState */
220 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700221 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700222
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700223 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800224 // protects mRingerMode
225 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800228 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
Mike Lockwood47676902011-11-08 10:31:21 -0800231 // Internally master volume is a float in the 0.0 - 1.0 range,
232 // but to support integer based AudioManager API we translate it to 0 - 100
233 private static final int MAX_MASTER_VOLUME = 100;
234
Lei Zhang6c798972012-03-02 11:40:12 -0800235 // Maximum volume adjust steps allowed in a single batch call.
236 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 /* Sound effect file names */
239 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700240 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
242 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
243 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
244 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700245 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246
Jared Suttles59820132009-08-13 21:50:52 -0500247 /** @hide Maximum volume index values for audio streams */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700248 private static final int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700249 5, // STREAM_VOICE_CALL
250 7, // STREAM_SYSTEM
251 7, // STREAM_RING
252 15, // STREAM_MUSIC
253 7, // STREAM_ALARM
254 7, // STREAM_NOTIFICATION
255 15, // STREAM_BLUETOOTH_SCO
256 7, // STREAM_SYSTEM_ENFORCED
257 15, // STREAM_DTMF
258 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500259 };
Eric Laurent6d517662012-04-23 18:42:39 -0700260 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700261 * of another stream: This avoids multiplying the volume settings for hidden
262 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700263 * NOTE: do not create loops in aliases!
264 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700265 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700266 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
267 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
268 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
269 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700270 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
271 AudioSystem.STREAM_RING, // STREAM_SYSTEM
272 AudioSystem.STREAM_RING, // STREAM_RING
273 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
274 AudioSystem.STREAM_ALARM, // STREAM_ALARM
275 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
276 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
277 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
278 AudioSystem.STREAM_RING, // STREAM_DTMF
279 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700280 };
Eric Laurent212532b2014-07-21 15:43:18 -0700281 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
282 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
283 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
284 AudioSystem.STREAM_MUSIC, // STREAM_RING
285 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
286 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
287 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
288 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
289 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
290 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
291 AudioSystem.STREAM_MUSIC // STREAM_TTS
292 };
293 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700294 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400295 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700296 AudioSystem.STREAM_RING, // STREAM_RING
297 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
298 AudioSystem.STREAM_ALARM, // STREAM_ALARM
299 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
300 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400301 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
302 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700303 AudioSystem.STREAM_MUSIC // STREAM_TTS
304 };
305 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700306
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700307 /**
308 * Map AudioSystem.STREAM_* constants to app ops. This should be used
309 * after mapping through mStreamVolumeAlias.
310 */
311 private static final int[] STEAM_VOLUME_OPS = new int[] {
312 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
313 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
314 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
315 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
316 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
317 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
318 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
319 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
320 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
321 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
322 };
323
Eric Laurent83a017b2013-03-19 18:15:31 -0700324 private final boolean mUseFixedVolume;
325
Eric Laurentbffc3d12012-05-07 17:43:49 -0700326 // stream names used by dumpStreamStates()
John Spurlock1af30c72014-03-10 08:33:35 -0400327 private static final String[] STREAM_NAMES = new String[] {
Eric Laurentbffc3d12012-05-07 17:43:49 -0700328 "STREAM_VOICE_CALL",
329 "STREAM_SYSTEM",
330 "STREAM_RING",
331 "STREAM_MUSIC",
332 "STREAM_ALARM",
333 "STREAM_NOTIFICATION",
334 "STREAM_BLUETOOTH_SCO",
335 "STREAM_SYSTEM_ENFORCED",
336 "STREAM_DTMF",
337 "STREAM_TTS"
338 };
339
Glenn Kasten30c918c2011-11-10 17:56:41 -0800340 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 public void onError(int error) {
342 switch (error) {
343 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700344 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
345 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 break;
347 default:
348 break;
349 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 };
352
353 /**
354 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
355 * {@link AudioManager#RINGER_MODE_SILENT}, or
356 * {@link AudioManager#RINGER_MODE_VIBRATE}.
357 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800358 // protected by mSettingsLock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 private int mRingerMode;
360
Eric Laurent9bcf4012009-06-12 06:09:28 -0700361 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700362 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700363
Eric Laurent5b4e6542010-03-19 20:02:21 -0700364 // Streams currently muted by ringer mode
365 private int mRingerModeMutedStreams;
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 /** @see System#MUTE_STREAMS_AFFECTED */
368 private int mMuteAffectedStreams;
369
370 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700371 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
372 * mVibrateSetting is just maintained during deprecation period but vibration policy is
373 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 */
375 private int mVibrateSetting;
376
Eric Laurentbffc3d12012-05-07 17:43:49 -0700377 // Is there a vibrator
378 private final boolean mHasVibrator;
379
Eric Laurenta553c252009-07-17 12:17:14 -0700380 // Broadcast receiver for device connections intent broadcasts
381 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
382
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700383 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800384 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700385
386 // Forced device usage for communications
387 private int mForcedUseForComm;
388
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500389 // True if we have master volume support
390 private final boolean mUseMasterVolume;
391
Mike Lockwood97606472012-02-09 11:24:10 -0800392 private final int[] mMasterVolumeRamp;
393
Eric Laurent9272b4b2010-01-23 17:12:59 -0800394 // List of binder death handlers for setMode() client processes.
395 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800396 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800397
Eric Laurent3def1ee2010-03-17 23:26:26 -0700398 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800399 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700400
401 // BluetoothHeadset API to control SCO connection
402 private BluetoothHeadset mBluetoothHeadset;
403
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700404 // Bluetooth headset device
405 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700406
Eric Laurent62ef7672010-11-24 10:58:32 -0800407 // Indicate if SCO audio connection is currently active and if the initiator is
408 // audio service (internal) or bluetooth headset (external)
409 private int mScoAudioState;
410 // SCO audio state is not active
411 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700412 // SCO audio activation request waiting for headset service to connect
413 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700414 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700415 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
416 // SCO audio deactivation request waiting for headset service to connect
417 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
418
Eric Laurent62ef7672010-11-24 10:58:32 -0800419 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
420 // in call audio)
421 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700422 // Deactivation request for all SCO connections (initiated by audio mode change)
423 // waiting for headset service to connect
424 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
425
Eric Laurentc18c9132013-04-12 17:24:56 -0700426 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
427 // originated from an app targeting an API version before JB MR2 and raw audio after that.
428 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700429 // SCO audio mode is undefined
430 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700431 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
432 private static final int SCO_MODE_VIRTUAL_CALL = 0;
433 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
434 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700435 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
436 private static final int SCO_MODE_VR = 2;
437
438 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700439
Eric Laurentdc03c612011-04-01 10:59:41 -0700440 // Current connection state indicated by bluetooth headset
441 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800442
Eric Laurenta60e2122010-12-28 16:49:07 -0800443 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700444 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800445 // listener for SoundPool sample load completion indication
446 private SoundPoolCallback mSoundPoolCallBack;
447 // thread for SoundPool listener
448 private SoundPoolListenerThread mSoundPoolListenerThread;
449 // message looper for SoundPool listener
450 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700451 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700452 private static int sSoundEffectVolumeDb;
Eric Laurent9903e262012-09-21 18:10:32 -0700453 // getActiveStreamType() will return:
454 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
455 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
Eric Laurent25101b02011-02-02 09:33:30 -0800456 // stopped
Eric Laurent9903e262012-09-21 18:10:32 -0700457 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
Eric Laurent25101b02011-02-02 09:33:30 -0800458 // previous volume adjustment direction received by checkForRingerModeChange()
459 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800460 // Keyguard manager proxy
461 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700462 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
463 // is controlled by Vol keys.
464 private int mVolumeControlStream = -1;
465 private final Object mForceControlStreamLock = new Object();
466 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
467 // server process so in theory it is not necessary to monitor the client death.
468 // However it is good to be ready for future evolutions.
469 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700470 // Used to play ringtones outside system_server
471 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800472
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700473 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700474 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700475
Eric Laurent78472112012-05-21 08:57:21 -0700476 // Request to override default use of A2DP for media.
477 private boolean mBluetoothA2dpEnabled;
478 private final Object mBluetoothA2dpEnabledLock = new Object();
479
Dianne Hackborn632ca412012-06-14 19:34:10 -0700480 // Monitoring of audio routes. Protected by mCurAudioRoutes.
481 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
482 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
483 = new RemoteCallbackList<IAudioRoutesObserver>();
484
Eric Laurent4bbcc652012-09-24 14:26:30 -0700485 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700486 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700487 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700488 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
489 AudioSystem.DEVICE_OUT_HDMI_ARC |
490 AudioSystem.DEVICE_OUT_SPDIF |
491 AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700492
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700493 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700494 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700495 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700496
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700497 private boolean mDockAudioMediaEnabled = true;
498
Eric Laurent08ed1b92012-11-05 14:54:12 -0800499 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
500
Eric Laurentfde16d52012-12-03 14:42:39 -0800501 // Used when safe volume warning message display is requested by setStreamVolume(). In this
502 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
503 // and used later when/if disableSafeMediaVolume() is called.
504 private StreamVolumeCommand mPendingVolumeCommand;
505
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700506 private PowerManager.WakeLock mAudioEventWakeLock;
507
508 private final MediaFocusControl mMediaFocusControl;
509
John Du5a0cf7a2013-07-19 11:30:34 -0700510 // Reference to BluetoothA2dp to query for AbsoluteVolume.
511 private BluetoothA2dp mA2dp;
512 private final Object mA2dpAvrcpLock = new Object();
513 // If absolute volume is supported in AVRCP device
514 private boolean mAvrcpAbsVolSupported = false;
515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 ///////////////////////////////////////////////////////////////////////////
517 // Construction
518 ///////////////////////////////////////////////////////////////////////////
519
520 /** @hide */
521 public AudioService(Context context) {
522 mContext = context;
523 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700524 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700525
526 if (mContext.getResources().getBoolean(
527 com.android.internal.R.bool.config_voice_capable)) {
528 mPlatformType = PLATFORM_VOICE;
529 } else if (context.getPackageManager().hasSystemFeature(
530 PackageManager.FEATURE_TELEVISION)) {
531 mPlatformType = PLATFORM_TELEVISION;
532 } else {
533 mPlatformType = PLATFORM_DEFAULT;
534 }
Jared Suttles59820132009-08-13 21:50:52 -0500535
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700536 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700537 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700538
Eric Laurentbffc3d12012-05-07 17:43:49 -0700539 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
540 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
541
Jared Suttles59820132009-08-13 21:50:52 -0500542 // Intialized volume
543 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
544 "ro.config.vc_call_vol_steps",
545 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
546
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700547 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700548 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800549
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700550 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700553
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700554 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400555 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700556
Eric Laurentdfb881f2013-07-18 14:41:39 -0700557 AudioSystem.setErrorCallback(mAudioSystemCallback);
558
Eric Laurentdd45d012012-10-08 09:04:34 -0700559 boolean cameraSoundForced = mContext.getResources().getBoolean(
560 com.android.internal.R.bool.config_camera_sound_forced);
561 mCameraSoundForced = new Boolean(cameraSoundForced);
562 sendMsg(mAudioHandler,
563 MSG_SET_FORCE_USE,
564 SENDMSG_QUEUE,
565 AudioSystem.FOR_SYSTEM,
566 cameraSoundForced ?
567 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
568 null,
569 0);
570
Eric Laurent05274f32012-11-29 12:48:18 -0800571 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
572 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
573 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
574 // The default safe volume index read here will be replaced by the actual value when
575 // the mcc is read by onConfigureSafeVolume()
576 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
577 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
578
Eric Laurent83a017b2013-03-19 18:15:31 -0700579 mUseFixedVolume = mContext.getResources().getBoolean(
580 com.android.internal.R.bool.config_useFixedVolume);
581
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700582 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
583 // array initialized by updateStreamVolumeAlias()
584 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700586 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700587 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700588
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700589 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700590
591 // Call setRingerModeInt() to apply correct mute
592 // state on streams affected by ringer mode.
593 mRingerModeMutedStreams = 0;
594 setRingerModeInt(getRingerMode(), false);
595
Eric Laurenta553c252009-07-17 12:17:14 -0700596 // Register for device connection intent broadcasts.
597 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700598 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700599 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
600 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent59f48272012-04-05 19:42:21 -0700601 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
602 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700603 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
604 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700605 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700606 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700607
Eric Laurentd640bd32012-09-28 18:01:48 -0700608 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700609 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700610 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
611 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700612 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700613 // initialize orientation in AudioSystem
614 setOrientationForAudioSystem();
615 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700616 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
617 if (mMonitorRotation) {
618 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
619 .getDefaultDisplay().getRotation();
620 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
621 // initialize rotation in AudioSystem
622 setRotationForAudioSystem();
623 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700624
Eric Laurenta553c252009-07-17 12:17:14 -0700625 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500626
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500627 mUseMasterVolume = context.getResources().getBoolean(
628 com.android.internal.R.bool.config_useMasterVolume);
Mike Lockwood90631542012-01-06 11:20:37 -0500629 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800630
631 mMasterVolumeRamp = context.getResources().getIntArray(
632 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent78472112012-05-21 08:57:21 -0700633
RoboErik0dac35a2014-08-12 15:48:49 -0700634 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 }
636
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700637 public void systemReady() {
638 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
639 0, 0, null, 0);
640 }
641
642 public void onSystemReady() {
643 mSystemReady = true;
644 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
645 0, 0, null, 0);
646
647 mKeyguardManager =
648 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
649 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
650 resetBluetoothSco();
651 getBluetoothHeadset();
652 //FIXME: this is to maintain compatibility with deprecated intent
653 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
654 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
655 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
656 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
657 sendStickyBroadcastToAll(newIntent);
658
659 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
660 if (adapter != null) {
661 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
662 BluetoothProfile.A2DP);
663 }
664
Eric Laurent212532b2014-07-21 15:43:18 -0700665 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900666 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700667 if (mHdmiManager != null) {
668 synchronized (mHdmiManager) {
669 mHdmiTvClient = mHdmiManager.getTvClient();
670 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
671 mHdmiCecSink = false;
672 }
673 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900674
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700675 sendMsg(mAudioHandler,
676 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
677 SENDMSG_REPLACE,
678 0,
679 0,
680 null,
681 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
682 }
683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 private void createAudioSystemThread() {
685 mAudioSystemThread = new AudioSystemThread();
686 mAudioSystemThread.start();
687 waitForAudioHandlerCreation();
688 }
689
690 /** Waits for the volume handler to be created by the other thread. */
691 private void waitForAudioHandlerCreation() {
692 synchronized(this) {
693 while (mAudioHandler == null) {
694 try {
695 // Wait for mAudioHandler to be set by the other thread
696 wait();
697 } catch (InterruptedException e) {
698 Log.e(TAG, "Interrupted while waiting on volume handler.");
699 }
700 }
701 }
702 }
703
Eric Laurent24482012012-05-10 09:41:17 -0700704 private void checkAllAliasStreamVolumes() {
705 int numStreamTypes = AudioSystem.getNumStreamTypes();
706 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
707 if (streamType != mStreamVolumeAlias[streamType]) {
708 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700709 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent24482012012-05-10 09:41:17 -0700710 }
711 // apply stream volume
Eric Laurent42b041e2013-03-29 11:36:03 -0700712 if (!mStreamStates[streamType].isMuted()) {
Eric Laurent24482012012-05-10 09:41:17 -0700713 mStreamStates[streamType].applyAllVolumes();
714 }
715 }
716 }
717
Eric Laurent212532b2014-07-21 15:43:18 -0700718 private void checkAllFixedVolumeDevices()
719 {
720 int numStreamTypes = AudioSystem.getNumStreamTypes();
721 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
722 mStreamStates[streamType].checkFixedVolumeDevices();
723 }
724 }
725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 int numStreamTypes = AudioSystem.getNumStreamTypes();
728 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
729
730 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700731 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700732 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733
Eric Laurent212532b2014-07-21 15:43:18 -0700734 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700735 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
737
Eric Laurentbffc3d12012-05-07 17:43:49 -0700738 private void dumpStreamStates(PrintWriter pw) {
739 pw.println("\nStream volumes (device: index)");
740 int numStreamTypes = AudioSystem.getNumStreamTypes();
741 for (int i = 0; i < numStreamTypes; i++) {
742 pw.println("- "+STREAM_NAMES[i]+":");
743 mStreamStates[i].dump(pw);
744 pw.println("");
745 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700746 pw.print("\n- mute affected streams = 0x");
747 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700748 }
749
John Spurlock1af30c72014-03-10 08:33:35 -0400750 /** @hide */
751 public static String streamToString(int stream) {
752 if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
753 if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
754 return "UNKNOWN_STREAM_" + stream;
755 }
Eric Laurent6d517662012-04-23 18:42:39 -0700756
757 private void updateStreamVolumeAlias(boolean updateVolumes) {
758 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700759
760 switch (mPlatformType) {
761 case PLATFORM_VOICE:
762 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700763 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700764 break;
765 case PLATFORM_TELEVISION:
766 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
767 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
768 break;
769 default:
770 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700771 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
772 }
Eric Laurent212532b2014-07-21 15:43:18 -0700773
774 if (isPlatformTelevision()) {
775 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700776 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700777 if (isInCommunication()) {
778 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
779 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
780 } else {
781 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
782 }
Eric Laurent6d517662012-04-23 18:42:39 -0700783 }
Eric Laurent212532b2014-07-21 15:43:18 -0700784
Eric Laurent6d517662012-04-23 18:42:39 -0700785 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
786 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700787 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700788 // apply stream mute states according to new value of mRingerModeAffectedStreams
789 setRingerModeInt(getRingerMode(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700790 sendMsg(mAudioHandler,
791 MSG_SET_ALL_VOLUMES,
792 SENDMSG_QUEUE,
793 0,
794 0,
795 mStreamStates[AudioSystem.STREAM_DTMF], 0);
796 }
797 }
798
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700799 private void readDockAudioSettings(ContentResolver cr)
800 {
801 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700802 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700803
804 if (mDockAudioMediaEnabled) {
805 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
806 } else {
807 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
808 }
809
810 sendMsg(mAudioHandler,
811 MSG_SET_FORCE_USE,
812 SENDMSG_QUEUE,
813 AudioSystem.FOR_DOCK,
814 mDockAudioMediaEnabled ?
815 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
816 null,
817 0);
818 }
819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 private void readPersistedSettings() {
821 final ContentResolver cr = mContentResolver;
822
Eric Laurentbffc3d12012-05-07 17:43:49 -0700823 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700824 Settings.Global.getInt(
825 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700826 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700827 // sanity check in case the settings are restored from a device with incompatible
828 // ringer modes
Glenn Kastenba195eb2011-12-13 09:30:40 -0800829 if (!AudioManager.isValidRingerMode(ringerMode)) {
830 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700831 }
832 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
833 ringerMode = AudioManager.RINGER_MODE_SILENT;
834 }
835 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700836 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800837 }
Eric Laurent212532b2014-07-21 15:43:18 -0700838 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700839 ringerMode = AudioManager.RINGER_MODE_NORMAL;
840 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800841 synchronized(mSettingsLock) {
842 mRingerMode = ringerMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843
Eric Laurentdd45d012012-10-08 09:04:34 -0700844 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
845 // are still needed while setVibrateSetting() and getVibrateSetting() are being
846 // deprecated.
847 mVibrateSetting = getValueForVibrateSetting(0,
848 AudioManager.VIBRATE_TYPE_NOTIFICATION,
849 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
850 : AudioManager.VIBRATE_SETTING_OFF);
851 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
852 AudioManager.VIBRATE_TYPE_RINGER,
853 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
854 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700856 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700857 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800858 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700859
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700860 mMuteAffectedStreams = System.getIntForUser(cr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 System.MUTE_STREAMS_AFFECTED,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700862 ((1 << AudioSystem.STREAM_MUSIC)|
863 (1 << AudioSystem.STREAM_RING)|
864 (1 << AudioSystem.STREAM_SYSTEM)),
865 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700867 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
868 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700869 if (mUseFixedVolume) {
870 masterMute = false;
871 AudioSystem.setMasterVolume(1.0f);
872 }
Justin Koh57978ed2012-04-03 17:37:58 -0700873 AudioSystem.setMasterMute(masterMute);
874 broadcastMasterMuteStatus(masterMute);
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 // Each stream will read its own persisted settings
877
878 // Broadcast the sticky intent
Glenn Kastenba195eb2011-12-13 09:30:40 -0800879 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
881 // Broadcast vibrate settings
882 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
883 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700884
John Spurlock33f4e042014-07-11 13:10:58 -0400885 // Load settings for the volume controller
886 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 }
888
Eric Laurenta553c252009-07-17 12:17:14 -0700889 private int rescaleIndex(int index, int srcStream, int dstStream) {
890 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892
893 ///////////////////////////////////////////////////////////////////////////
894 // IPC methods
895 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700897 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
898 String callingPackage) {
John Spurlockae641c92014-06-30 18:11:40 -0400899 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
900 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800901 int streamType;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700902 if (mVolumeControlStream != -1) {
903 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800904 } else {
905 streamType = getActiveStreamType(suggestedStreamType);
906 }
John Spurlock33f4e042014-07-11 13:10:58 -0400907 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908
RoboErik2811dd32014-08-12 09:48:13 -0700909 // Play sounds on STREAM_RING only.
910 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400911 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 flags &= ~AudioManager.FLAG_PLAY_SOUND;
913 }
914
John Spurlock33f4e042014-07-11 13:10:58 -0400915 // For notifications/ring, show the ui before making any adjustments
916 if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
917 direction = 0;
918 flags &= ~AudioManager.FLAG_PLAY_SOUND;
919 flags &= ~AudioManager.FLAG_VIBRATE;
920 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
921 }
922
RoboErik2811dd32014-08-12 09:48:13 -0700923 adjustStreamVolume(streamType, direction, flags, callingPackage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 }
925
926 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700927 public void adjustStreamVolume(int streamType, int direction, int flags,
928 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -0700929 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
930 }
931
932 private void adjustStreamVolume(int streamType, int direction, int flags,
933 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700934 if (mUseFixedVolume) {
935 return;
936 }
John Spurlockae641c92014-06-30 18:11:40 -0400937 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
938 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 ensureValidDirection(direction);
941 ensureValidStreamType(streamType);
942
Eric Laurent96a33d12011-11-08 10:31:57 -0800943 // use stream type alias here so that streams with same alias have the same behavior,
944 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
945 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -0700946 int streamTypeAlias = mStreamVolumeAlias[streamType];
Eric Laurentb024c302011-10-14 17:19:27 -0700947 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800948
949 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -0800950
Eric Laurent42b041e2013-03-29 11:36:03 -0700951 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -0800953 int step;
Eric Laurent24482012012-05-10 09:41:17 -0700954
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700955 // skip a2dp absolute volume control request when the device
956 // is not an a2dp device
957 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
958 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
959 return;
960 }
961
RoboErik0dac35a2014-08-12 15:48:49 -0700962 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
963 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700964 return;
965 }
966
Eric Laurentfde16d52012-12-03 14:42:39 -0800967 // reset any pending volume command
968 synchronized (mSafeMediaVolumeState) {
969 mPendingVolumeCommand = null;
970 }
971
Eric Laurent3ef75492012-11-28 12:12:23 -0800972 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
973 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
974 ((device & mFixedVolumeDevices) != 0)) {
975 flags |= AudioManager.FLAG_FIXED_VOLUME;
976
977 // Always toggle between max safe volume and 0 for fixed volume devices where safe
978 // volume is enforced, and max and 0 for the others.
979 // This is simulated by stepping by the full allowed volume range
980 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
981 (device & mSafeMediaVolumeDevices) != 0) {
982 step = mSafeMediaVolumeIndex;
983 } else {
984 step = streamState.getMaxIndex();
985 }
986 if (aliasIndex != 0) {
987 aliasIndex = step;
988 }
989 } else {
990 // convert one UI step (+/-1) into a number of internal units on the stream alias
991 step = rescaleIndex(10, streamType, streamTypeAlias);
992 }
993
Eric Laurent42b041e2013-03-29 11:36:03 -0700994 // If either the client forces allowing ringer modes for this adjustment,
995 // or the stream type is one that is affected by ringer modes
996 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
997 (streamTypeAlias == getMasterStreamType())) {
998 int ringerMode = getRingerMode();
999 // do not vibrate if already in vibrate mode
1000 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1001 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001002 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001003 // Check if the ringer mode changes with this volume adjustment. If
1004 // it does, it will handle adjusting the volume, so we won't below
John Spurlocka11b4af2014-06-01 11:52:23 -04001005 final int result = checkForRingerModeChange(aliasIndex, direction, step);
1006 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1007 // If suppressing a volume adjustment in silent mode, display the UI hint
1008 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1009 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1010 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001011 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001012
Eric Laurent42b041e2013-03-29 11:36:03 -07001013 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001014
Eric Laurent42b041e2013-03-29 11:36:03 -07001015 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001016
John Du5a0cf7a2013-07-19 11:30:34 -07001017 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001018 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1019 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1020 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1021 synchronized (mA2dpAvrcpLock) {
1022 if (mA2dp != null && mAvrcpAbsVolSupported) {
1023 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1024 }
John Du5a0cf7a2013-07-19 11:30:34 -07001025 }
1026 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001027
Eric Laurent42b041e2013-03-29 11:36:03 -07001028 if ((direction == AudioManager.ADJUST_RAISE) &&
1029 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
1030 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001031 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurent42b041e2013-03-29 11:36:03 -07001032 } else if (streamState.adjustIndex(direction * step, device)) {
1033 // Post message to set system volume (it in turn will post a message
1034 // to persist). Do not change volume if stream is muted.
1035 sendMsg(mAudioHandler,
1036 MSG_SET_DEVICE_VOLUME,
1037 SENDMSG_QUEUE,
1038 device,
1039 0,
1040 streamState,
1041 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001042 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001043
1044 // Check if volume update should be send to Hdmi system audio.
1045 int newIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent212532b2014-07-21 15:43:18 -07001046 if (mHdmiManager != null) {
1047 synchronized (mHdmiManager) {
1048 if (mHdmiTvClient != null &&
1049 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1050 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1051 oldIndex != newIndex) {
1052 int maxIndex = getStreamMaxVolume(streamType);
1053 synchronized (mHdmiTvClient) {
1054 if (mHdmiSystemAudioSupported) {
1055 mHdmiTvClient.setSystemAudioVolume(
1056 (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
1057 }
1058 }
1059 }
1060 // mHdmiCecSink true => mHdmiPlaybackClient != null
1061 if (mHdmiCecSink &&
1062 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1063 oldIndex != newIndex) {
1064 synchronized (mHdmiPlaybackClient) {
1065 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
1066 KeyEvent.KEYCODE_VOLUME_UP;
1067 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1068 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1069 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001070 }
1071 }
1072 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001073 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001074 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001075 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 }
1077
Dianne Hackborn961cae92013-03-20 14:59:43 -07001078 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001079 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001080 if (mUseFixedVolume) {
1081 return;
1082 }
Lei Zhang6c798972012-03-02 11:40:12 -08001083 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001084 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1085 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001086 int numSteps = Math.abs(steps);
1087 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1088 for (int i = 0; i < numSteps; ++i) {
1089 delta = findVolumeDelta(direction, volume);
1090 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001091 }
RoboErik24b082f2012-02-24 14:21:16 -08001092
Lei Zhang6c798972012-03-02 11:40:12 -08001093 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001094 setMasterVolume(volume, flags, callingPackage);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001095 }
1096
Eric Laurentfde16d52012-12-03 14:42:39 -08001097 // StreamVolumeCommand contains the information needed to defer the process of
1098 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1099 class StreamVolumeCommand {
1100 public final int mStreamType;
1101 public final int mIndex;
1102 public final int mFlags;
1103 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001104
Eric Laurentfde16d52012-12-03 14:42:39 -08001105 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1106 mStreamType = streamType;
1107 mIndex = index;
1108 mFlags = flags;
1109 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001110 }
John Spurlock35134602014-07-24 18:10:48 -04001111
1112 @Override
1113 public String toString() {
1114 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1115 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1116 .append(mDevice).append('}').toString();
1117 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001118 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001119
Eric Laurentfde16d52012-12-03 14:42:39 -08001120 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001121 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001122 // setting volume on master stream type also controls silent mode
1123 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1124 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1125 int newRingerMode;
1126 if (index == 0) {
1127 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001128 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1129 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001130 } else {
1131 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1132 }
1133 setRingerMode(newRingerMode);
1134 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001135 }
1136
1137 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001138 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001139 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1140 }
1141
1142 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1143 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001144 if (mUseFixedVolume) {
1145 return;
1146 }
1147
Eric Laurentfde16d52012-12-03 14:42:39 -08001148 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001149 int streamTypeAlias = mStreamVolumeAlias[streamType];
1150 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001151
1152 final int device = getDeviceForStream(streamType);
1153 int oldIndex;
1154
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001155 // skip a2dp absolute volume control request when the device
1156 // is not an a2dp device
1157 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1158 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1159 return;
1160 }
1161
RoboErik0dac35a2014-08-12 15:48:49 -07001162 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1163 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001164 return;
1165 }
1166
Eric Laurentfde16d52012-12-03 14:42:39 -08001167 synchronized (mSafeMediaVolumeState) {
1168 // reset any pending volume command
1169 mPendingVolumeCommand = null;
1170
Eric Laurent42b041e2013-03-29 11:36:03 -07001171 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001172
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001173 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001174
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001175 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1176 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1177 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1178 synchronized (mA2dpAvrcpLock) {
1179 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001180 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001181 }
John Du5a0cf7a2013-07-19 11:30:34 -07001182 }
1183 }
1184
Eric Laurent212532b2014-07-21 15:43:18 -07001185 if (mHdmiManager != null) {
1186 synchronized (mHdmiManager) {
1187 if (mHdmiTvClient != null &&
1188 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1189 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1190 oldIndex != index) {
1191 int maxIndex = getStreamMaxVolume(streamType);
1192 synchronized (mHdmiTvClient) {
1193 if (mHdmiSystemAudioSupported) {
1194 mHdmiTvClient.setSystemAudioVolume(
1195 (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
1196 }
1197 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001198 }
1199 }
1200 }
1201
Eric Laurentfde16d52012-12-03 14:42:39 -08001202 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001203 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001204 ((device & mFixedVolumeDevices) != 0)) {
1205 flags |= AudioManager.FLAG_FIXED_VOLUME;
1206
1207 // volume is either 0 or max allowed for fixed volume devices
1208 if (index != 0) {
1209 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1210 (device & mSafeMediaVolumeDevices) != 0) {
1211 index = mSafeMediaVolumeIndex;
1212 } else {
1213 index = streamState.getMaxIndex();
1214 }
1215 }
1216 }
1217
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001218 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001219 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001220 mPendingVolumeCommand = new StreamVolumeCommand(
1221 streamType, index, flags, device);
1222 } else {
1223 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001224 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001225 }
1226 }
Eric Laurent25101b02011-02-02 09:33:30 -08001227 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 }
1229
Eric Laurent45c90ce2012-04-24 18:44:22 -07001230 /** @see AudioManager#forceVolumeControlStream(int) */
1231 public void forceVolumeControlStream(int streamType, IBinder cb) {
1232 synchronized(mForceControlStreamLock) {
1233 mVolumeControlStream = streamType;
1234 if (mVolumeControlStream == -1) {
1235 if (mForceControlStreamClient != null) {
1236 mForceControlStreamClient.release();
1237 mForceControlStreamClient = null;
1238 }
1239 } else {
1240 mForceControlStreamClient = new ForceControlStreamClient(cb);
1241 }
1242 }
1243 }
1244
1245 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1246 private IBinder mCb; // To be notified of client's death
1247
1248 ForceControlStreamClient(IBinder cb) {
1249 if (cb != null) {
1250 try {
1251 cb.linkToDeath(this, 0);
1252 } catch (RemoteException e) {
1253 // Client has died!
1254 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1255 cb = null;
1256 }
1257 }
1258 mCb = cb;
1259 }
1260
1261 public void binderDied() {
1262 synchronized(mForceControlStreamLock) {
1263 Log.w(TAG, "SCO client died");
1264 if (mForceControlStreamClient != this) {
1265 Log.w(TAG, "unregistered control stream client died");
1266 } else {
1267 mForceControlStreamClient = null;
1268 mVolumeControlStream = -1;
1269 }
1270 }
1271 }
1272
1273 public void release() {
1274 if (mCb != null) {
1275 mCb.unlinkToDeath(this, 0);
1276 mCb = null;
1277 }
1278 }
1279 }
1280
Lei Zhang6c798972012-03-02 11:40:12 -08001281 private int findVolumeDelta(int direction, int volume) {
1282 int delta = 0;
1283 if (direction == AudioManager.ADJUST_RAISE) {
1284 if (volume == MAX_MASTER_VOLUME) {
1285 return 0;
1286 }
1287 // This is the default value if we make it to the end
1288 delta = mMasterVolumeRamp[1];
1289 // If we're raising the volume move down the ramp array until we
1290 // find the volume we're above and use that groups delta.
1291 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1292 if (volume >= mMasterVolumeRamp[i - 1]) {
1293 delta = mMasterVolumeRamp[i];
1294 break;
1295 }
1296 }
1297 } else if (direction == AudioManager.ADJUST_LOWER){
1298 if (volume == 0) {
1299 return 0;
1300 }
1301 int length = mMasterVolumeRamp.length;
1302 // This is the default value if we make it to the end
1303 delta = -mMasterVolumeRamp[length - 1];
1304 // If we're lowering the volume move up the ramp array until we
1305 // find the volume we're below and use the group below it's delta
1306 for (int i = 2; i < length; i += 2) {
1307 if (volume <= mMasterVolumeRamp[i]) {
1308 delta = -mMasterVolumeRamp[i - 1];
1309 break;
1310 }
1311 }
1312 }
1313 return delta;
1314 }
1315
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001316 private void sendBroadcastToAll(Intent intent) {
1317 final long ident = Binder.clearCallingIdentity();
1318 try {
1319 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1320 } finally {
1321 Binder.restoreCallingIdentity(ident);
1322 }
1323 }
1324
1325 private void sendStickyBroadcastToAll(Intent intent) {
1326 final long ident = Binder.clearCallingIdentity();
1327 try {
1328 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1329 } finally {
1330 Binder.restoreCallingIdentity(ident);
1331 }
1332 }
1333
Eric Laurent25101b02011-02-02 09:33:30 -08001334 // UI update and Broadcast Intent
1335 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001336 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001337 streamType = AudioSystem.STREAM_NOTIFICATION;
1338 }
1339
John Spurlock3346a802014-05-20 16:25:37 -04001340 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001341
Eric Laurent4bbcc652012-09-24 14:26:30 -07001342 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1343 oldIndex = (oldIndex + 5) / 10;
1344 index = (index + 5) / 10;
1345 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1346 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1347 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1348 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1349 sendBroadcastToAll(intent);
1350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 }
1352
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001353 // UI update and Broadcast Intent
1354 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
John Spurlock3346a802014-05-20 16:25:37 -04001355 mVolumeController.postMasterVolumeChanged(flags);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001356
1357 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1358 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1359 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001360 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001361 }
1362
1363 // UI update and Broadcast Intent
1364 private void sendMasterMuteUpdate(boolean muted, int flags) {
John Spurlock3346a802014-05-20 16:25:37 -04001365 mVolumeController.postMasterMuteChanged(flags);
Justin Koh57978ed2012-04-03 17:37:58 -07001366 broadcastMasterMuteStatus(muted);
1367 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001368
Justin Koh57978ed2012-04-03 17:37:58 -07001369 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001370 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1371 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001372 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1373 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001374 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001375 }
1376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 * Sets the stream state's index, and posts a message to set system volume.
1379 * This will not call out to the UI. Assumes a valid stream type.
1380 *
1381 * @param streamType Type of the stream
1382 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001383 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 * @param force If true, set the volume even if the desired volume is same
1385 * as the current volume.
1386 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001387 private void setStreamVolumeInt(int streamType,
1388 int index,
1389 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001390 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001392
Eric Laurent42b041e2013-03-29 11:36:03 -07001393 if (streamState.setIndex(index, device) || force) {
1394 // Post message to set system volume (it in turn will post a message
1395 // to persist).
1396 sendMsg(mAudioHandler,
1397 MSG_SET_DEVICE_VOLUME,
1398 SENDMSG_QUEUE,
1399 device,
1400 0,
1401 streamState,
1402 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 }
1404 }
1405
1406 /** @see AudioManager#setStreamSolo(int, boolean) */
1407 public void setStreamSolo(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 for (int stream = 0; stream < mStreamStates.length; stream++) {
1413 if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 mStreamStates[stream].mute(cb, state);
1415 }
1416 }
1417
1418 /** @see AudioManager#setStreamMute(int, boolean) */
1419 public void setStreamMute(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001420 if (mUseFixedVolume) {
1421 return;
1422 }
1423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 if (isStreamAffectedByMute(streamType)) {
Eric Laurent212532b2014-07-21 15:43:18 -07001425 if (mHdmiManager != null) {
1426 synchronized (mHdmiManager) {
1427 if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
1428 synchronized (mHdmiTvClient) {
1429 if (mHdmiSystemAudioSupported) {
1430 mHdmiTvClient.setSystemAudioMute(state);
1431 }
1432 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001433 }
1434 }
1435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 mStreamStates[streamType].mute(cb, state);
1437 }
1438 }
1439
Eric Laurent25101b02011-02-02 09:33:30 -08001440 /** get stream mute state. */
1441 public boolean isStreamMute(int streamType) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001442 return mStreamStates[streamType].isMuted();
Eric Laurent25101b02011-02-02 09:33:30 -08001443 }
1444
Dianne Hackborn961cae92013-03-20 14:59:43 -07001445 /** @see AudioManager#setMasterMute(boolean, int) */
Julia Reynolds4a21b252014-06-04 11:11:43 -04001446 public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001447 if (mUseFixedVolume) {
1448 return;
1449 }
1450
Julia Reynolds4a21b252014-06-04 11:11:43 -04001451 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1452 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1453 return;
1454 }
1455
Jason Simmons1ce5b262012-02-02 13:00:17 -08001456 if (state != AudioSystem.getMasterMute()) {
1457 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001458 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001459 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Justin Koh57978ed2012-04-03 17:37:58 -07001460 : 0, 0, null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001461 sendMasterMuteUpdate(state, flags);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001462 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001463 }
1464
1465 /** get master mute state. */
1466 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001467 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001468 }
1469
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001470 protected static int getMaxStreamVolume(int streamType) {
1471 return MAX_STREAM_VOLUME[streamType];
1472 }
1473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 /** @see AudioManager#getStreamVolume(int) */
1475 public int getStreamVolume(int streamType) {
1476 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001477 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001478 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001479
Eric Laurent42b041e2013-03-29 11:36:03 -07001480 // by convention getStreamVolume() returns 0 when a stream is muted.
1481 if (mStreamStates[streamType].isMuted()) {
1482 index = 0;
1483 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001484 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
Eric Laurent4bbcc652012-09-24 14:26:30 -07001485 (device & mFixedVolumeDevices) != 0) {
1486 index = mStreamStates[streamType].getMaxIndex();
Eric Laurent4bbcc652012-09-24 14:26:30 -07001487 }
1488 return (index + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490
Mike Lockwood47676902011-11-08 10:31:21 -08001491 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001492 if (isMasterMute()) return 0;
1493 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001494 }
1495
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001496 public void setMasterVolume(int volume, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001497 if (mUseFixedVolume) {
1498 return;
1499 }
1500
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001501 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1502 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1503 return;
1504 }
1505
Mike Lockwood97606472012-02-09 11:24:10 -08001506 if (volume < 0) {
1507 volume = 0;
1508 } else if (volume > MAX_MASTER_VOLUME) {
1509 volume = MAX_MASTER_VOLUME;
1510 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001511 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1512 }
1513
1514 private void doSetMasterVolume(float volume, int flags) {
1515 // don't allow changing master volume when muted
1516 if (!AudioSystem.getMasterMute()) {
1517 int oldVolume = getMasterVolume();
1518 AudioSystem.setMasterVolume(volume);
1519
1520 int newVolume = getMasterVolume();
1521 if (newVolume != oldVolume) {
1522 // Post a persist master volume msg
1523 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1524 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001525 }
Justin Koh3caba512012-04-02 15:32:18 -07001526 // Send the volume update regardless whether there was a change.
1527 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001528 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001529 }
1530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 /** @see AudioManager#getStreamMaxVolume(int) */
1532 public int getStreamMaxVolume(int streamType) {
1533 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001534 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
1536
Mike Lockwood47676902011-11-08 10:31:21 -08001537 public int getMasterMaxVolume() {
1538 return MAX_MASTER_VOLUME;
1539 }
Eric Laurent25101b02011-02-02 09:33:30 -08001540
1541 /** Get last audible volume before stream was muted. */
1542 public int getLastAudibleStreamVolume(int streamType) {
1543 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001544 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001545 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001546 }
1547
Mike Lockwoodce952c82011-11-14 10:47:42 -08001548 /** Get last audible master volume before it was muted. */
1549 public int getLastAudibleMasterVolume() {
1550 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1551 }
1552
Dianne Hackborn961cae92013-03-20 14:59:43 -07001553 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001554 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001555 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001556 }
1557
Emily Bernier22c921a2014-05-28 11:01:32 -04001558 /** @see AudioManager#setMicrophoneMute(boolean) */
1559 public void setMicrophoneMute(boolean on, String callingPackage) {
1560 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1561 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1562 return;
1563 }
1564
1565 AudioSystem.muteMicrophone(on);
1566 }
1567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 /** @see AudioManager#getRingerMode() */
1569 public int getRingerMode() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001570 synchronized(mSettingsLock) {
1571 return mRingerMode;
1572 }
1573 }
1574
1575 private void ensureValidRingerMode(int ringerMode) {
1576 if (!AudioManager.isValidRingerMode(ringerMode)) {
1577 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580
1581 /** @see AudioManager#setRingerMode(int) */
1582 public void setRingerMode(int ringerMode) {
Eric Laurent212532b2014-07-21 15:43:18 -07001583 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001584 return;
1585 }
1586
Eric Laurent24482012012-05-10 09:41:17 -07001587 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1588 ringerMode = AudioManager.RINGER_MODE_SILENT;
1589 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001590 if (ringerMode != getRingerMode()) {
1591 setRingerModeInt(ringerMode, true);
1592 // Send sticky broadcast
1593 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 }
1595 }
1596
Eric Laurent4050c932009-07-08 02:52:14 -07001597 private void setRingerModeInt(int ringerMode, boolean persist) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001598 synchronized(mSettingsLock) {
1599 mRingerMode = ringerMode;
1600 }
Jason Parekhb1096152009-03-24 17:48:25 -07001601
Eric Laurent5b4e6542010-03-19 20:02:21 -07001602 // Mute stream if not previously muted by ringer mode and ringer mode
1603 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1604 // Unmute stream if previously muted by ringer mode and ringer mode
1605 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001606 int numStreamTypes = AudioSystem.getNumStreamTypes();
Eric Laurent5b4e6542010-03-19 20:02:21 -07001607 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1608 if (isStreamMutedByRingerMode(streamType)) {
1609 if (!isStreamAffectedByRingerMode(streamType) ||
Glenn Kastenba195eb2011-12-13 09:30:40 -08001610 ringerMode == AudioManager.RINGER_MODE_NORMAL) {
Eric Laurentb024c302011-10-14 17:19:27 -07001611 // ring and notifications volume should never be 0 when not silenced
1612 // on voice capable devices
Eric Laurent212532b2014-07-21 15:43:18 -07001613 if (isPlatformVoice() &&
Eric Laurent6d517662012-04-23 18:42:39 -07001614 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07001615 synchronized (mStreamStates[streamType]) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001616 Set set = mStreamStates[streamType].mIndex.entrySet();
Eric Laurent3172d5e2012-05-09 11:38:16 -07001617 Iterator i = set.iterator();
1618 while (i.hasNext()) {
1619 Map.Entry entry = (Map.Entry)i.next();
1620 if ((Integer)entry.getValue() == 0) {
1621 entry.setValue(10);
1622 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001623 }
1624 }
Eric Laurentb024c302011-10-14 17:19:27 -07001625 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001626 mStreamStates[streamType].mute(null, false);
1627 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent9bcf4012009-06-12 06:09:28 -07001628 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001629 } else {
1630 if (isStreamAffectedByRingerMode(streamType) &&
Glenn Kastenba195eb2011-12-13 09:30:40 -08001631 ringerMode != AudioManager.RINGER_MODE_NORMAL) {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001632 mStreamStates[streamType].mute(null, true);
1633 mRingerModeMutedStreams |= (1 << streamType);
1634 }
Jason Parekhb1096152009-03-24 17:48:25 -07001635 }
1636 }
Eric Laurenta553c252009-07-17 12:17:14 -07001637
Jason Parekhb1096152009-03-24 17:48:25 -07001638 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001639 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001640 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001641 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1642 }
Jason Parekhb1096152009-03-24 17:48:25 -07001643 }
1644
Mike Lockwood90631542012-01-06 11:20:37 -05001645 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001646 if (mUseFixedVolume) {
1647 AudioSystem.setMasterVolume(1.0f);
1648 return;
1649 }
Mike Lockwood90631542012-01-06 11:20:37 -05001650 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001651 float volume = Settings.System.getFloatForUser(mContentResolver,
1652 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001653 if (volume >= 0.0f) {
1654 AudioSystem.setMasterVolume(volume);
1655 }
1656 }
1657 }
1658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 /** @see AudioManager#shouldVibrate(int) */
1660 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001661 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662
1663 switch (getVibrateSetting(vibrateType)) {
1664
1665 case AudioManager.VIBRATE_SETTING_ON:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001666 return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667
1668 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001669 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670
1671 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001672 // return false, even for incoming calls
1673 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674
1675 default:
1676 return false;
1677 }
1678 }
1679
1680 /** @see AudioManager#getVibrateSetting(int) */
1681 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001682 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1684 }
1685
1686 /** @see AudioManager#setVibrateSetting(int, int) */
1687 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1688
Eric Laurentbffc3d12012-05-07 17:43:49 -07001689 if (!mHasVibrator) return;
1690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1692
1693 // Broadcast change
1694 broadcastVibrateSetting(vibrateType);
1695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 }
1697
1698 /**
1699 * @see #setVibrateSetting(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 */
1701 public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1702 int vibrateSetting) {
1703
1704 // First clear the existing setting. Each vibrate type has two bits in
1705 // the value. Note '3' is '11' in binary.
1706 existingValue &= ~(3 << (vibrateType * 2));
1707
1708 // Set into the old value
1709 existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1710
1711 return existingValue;
1712 }
1713
Eric Laurent9272b4b2010-01-23 17:12:59 -08001714 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1715 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001716 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001717 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1718
Eric Laurent9f103de2011-09-08 15:04:23 -07001719 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001720 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001721 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001722 }
1723
1724 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001725 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001726 synchronized(mSetModeDeathHandlers) {
1727 Log.w(TAG, "setMode() client died");
1728 int index = mSetModeDeathHandlers.indexOf(this);
1729 if (index < 0) {
1730 Log.w(TAG, "unregistered setMode() client died");
1731 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001732 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001733 }
1734 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001735 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1736 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001737 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001738 final long ident = Binder.clearCallingIdentity();
1739 disconnectBluetoothSco(newModeOwnerPid);
1740 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001741 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001742 }
1743
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001744 public int getPid() {
1745 return mPid;
1746 }
1747
Eric Laurent9272b4b2010-01-23 17:12:59 -08001748 public void setMode(int mode) {
1749 mMode = mode;
1750 }
1751
1752 public int getMode() {
1753 return mMode;
1754 }
1755
1756 public IBinder getBinder() {
1757 return mCb;
1758 }
1759 }
1760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001762 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001763 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 if (!checkAudioSettingsPermission("setMode()")) {
1765 return;
1766 }
Eric Laurenta553c252009-07-17 12:17:14 -07001767
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001768 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001769 return;
1770 }
1771
Eric Laurentd7454be2011-09-14 08:45:58 -07001772 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001773 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001774 if (mode == AudioSystem.MODE_CURRENT) {
1775 mode = mMode;
1776 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001777 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001778 }
1779 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1780 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001781 if (newModeOwnerPid != 0) {
1782 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001783 }
1784 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001785
Eric Laurent9f103de2011-09-08 15:04:23 -07001786 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001787 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001788 // any mode other than NORMAL.
Eric Laurentd7454be2011-09-14 08:45:58 -07001789 int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001790 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07001791 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001792 if (cb == null) {
1793 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001794 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001795 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001796
Eric Laurent9f103de2011-09-08 15:04:23 -07001797 SetModeDeathHandler hdlr = null;
1798 Iterator iter = mSetModeDeathHandlers.iterator();
1799 while (iter.hasNext()) {
1800 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1801 if (h.getPid() == pid) {
1802 hdlr = h;
1803 // Remove from client list so that it is re-inserted at top of list
1804 iter.remove();
1805 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1806 break;
1807 }
1808 }
1809 int status = AudioSystem.AUDIO_STATUS_OK;
1810 do {
1811 if (mode == AudioSystem.MODE_NORMAL) {
1812 // get new mode from client at top the list if any
1813 if (!mSetModeDeathHandlers.isEmpty()) {
1814 hdlr = mSetModeDeathHandlers.get(0);
1815 cb = hdlr.getBinder();
1816 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001817 if (DEBUG_MODE) {
1818 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
1819 + hdlr.mPid);
1820 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07001821 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001822 } else {
1823 if (hdlr == null) {
1824 hdlr = new SetModeDeathHandler(cb, pid);
1825 }
1826 // Register for client death notification
1827 try {
1828 cb.linkToDeath(hdlr, 0);
1829 } catch (RemoteException e) {
1830 // Client has died!
1831 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1832 }
1833
1834 // Last client to call setMode() is always at top of client list
1835 // as required by SetModeDeathHandler.binderDied()
1836 mSetModeDeathHandlers.add(0, hdlr);
1837 hdlr.setMode(mode);
1838 }
1839
1840 if (mode != mMode) {
1841 status = AudioSystem.setPhoneState(mode);
1842 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001843 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001844 mMode = mode;
1845 } else {
1846 if (hdlr != null) {
1847 mSetModeDeathHandlers.remove(hdlr);
1848 cb.unlinkToDeath(hdlr, 0);
1849 }
1850 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001851 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001852 mode = AudioSystem.MODE_NORMAL;
1853 }
1854 } else {
1855 status = AudioSystem.AUDIO_STATUS_OK;
1856 }
1857 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1858
1859 if (status == AudioSystem.AUDIO_STATUS_OK) {
1860 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07001861 if (mSetModeDeathHandlers.isEmpty()) {
1862 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1863 } else {
1864 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 }
1867 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001868 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001869 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1870 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07001871
1872 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001874 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 }
1876
1877 /** @see AudioManager#getMode() */
1878 public int getMode() {
1879 return mMode;
1880 }
1881
Eric Laurente78fced2013-03-15 16:03:47 -07001882 //==========================================================================================
1883 // Sound Effects
1884 //==========================================================================================
1885
1886 private static final String TAG_AUDIO_ASSETS = "audio_assets";
1887 private static final String ATTR_VERSION = "version";
1888 private static final String TAG_GROUP = "group";
1889 private static final String ATTR_GROUP_NAME = "name";
1890 private static final String TAG_ASSET = "asset";
1891 private static final String ATTR_ASSET_ID = "id";
1892 private static final String ATTR_ASSET_FILE = "file";
1893
1894 private static final String ASSET_FILE_VERSION = "1.0";
1895 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1896
Glenn Kasten167d1a22013-07-23 16:24:41 -07001897 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001898
1899 class LoadSoundEffectReply {
1900 public int mStatus = 1;
1901 };
1902
Eric Laurente78fced2013-03-15 16:03:47 -07001903 private void loadTouchSoundAssetDefaults() {
1904 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1905 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1906 SOUND_EFFECT_FILES_MAP[i][0] = 0;
1907 SOUND_EFFECT_FILES_MAP[i][1] = -1;
1908 }
1909 }
1910
1911 private void loadTouchSoundAssets() {
1912 XmlResourceParser parser = null;
1913
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001914 // only load assets once.
1915 if (!SOUND_EFFECT_FILES.isEmpty()) {
1916 return;
1917 }
1918
Eric Laurente78fced2013-03-15 16:03:47 -07001919 loadTouchSoundAssetDefaults();
1920
1921 try {
1922 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1923
1924 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1925 String version = parser.getAttributeValue(null, ATTR_VERSION);
1926 boolean inTouchSoundsGroup = false;
1927
1928 if (ASSET_FILE_VERSION.equals(version)) {
1929 while (true) {
1930 XmlUtils.nextElement(parser);
1931 String element = parser.getName();
1932 if (element == null) {
1933 break;
1934 }
1935 if (element.equals(TAG_GROUP)) {
1936 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1937 if (GROUP_TOUCH_SOUNDS.equals(name)) {
1938 inTouchSoundsGroup = true;
1939 break;
1940 }
1941 }
1942 }
1943 while (inTouchSoundsGroup) {
1944 XmlUtils.nextElement(parser);
1945 String element = parser.getName();
1946 if (element == null) {
1947 break;
1948 }
1949 if (element.equals(TAG_ASSET)) {
1950 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1951 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1952 int fx;
1953
1954 try {
1955 Field field = AudioManager.class.getField(id);
1956 fx = field.getInt(null);
1957 } catch (Exception e) {
1958 Log.w(TAG, "Invalid touch sound ID: "+id);
1959 continue;
1960 }
1961
1962 int i = SOUND_EFFECT_FILES.indexOf(file);
1963 if (i == -1) {
1964 i = SOUND_EFFECT_FILES.size();
1965 SOUND_EFFECT_FILES.add(file);
1966 }
1967 SOUND_EFFECT_FILES_MAP[fx][0] = i;
1968 } else {
1969 break;
1970 }
1971 }
1972 }
1973 } catch (Resources.NotFoundException e) {
1974 Log.w(TAG, "audio assets file not found", e);
1975 } catch (XmlPullParserException e) {
1976 Log.w(TAG, "XML parser exception reading touch sound assets", e);
1977 } catch (IOException e) {
1978 Log.w(TAG, "I/O exception reading touch sound assets", e);
1979 } finally {
1980 if (parser != null) {
1981 parser.close();
1982 }
1983 }
1984 }
1985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 /** @see AudioManager#playSoundEffect(int) */
1987 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001988 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 }
1990
1991 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07001993 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1994 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1995 return;
1996 }
1997
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001998 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 effectType, (int) (volume * 1000), null, 0);
2000 }
2001
2002 /**
2003 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002004 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 */
2006 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002007 int attempts = 3;
2008 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002009
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002010 synchronized (reply) {
2011 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2012 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002013 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002014 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002015 } catch (InterruptedException e) {
2016 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002017 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002018 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002020 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 }
2022
2023 /**
2024 * Unloads samples from the sound pool.
2025 * This method can be called to free some memory when
2026 * sound effects are disabled.
2027 */
2028 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002029 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 }
2031
Eric Laurenta60e2122010-12-28 16:49:07 -08002032 class SoundPoolListenerThread extends Thread {
2033 public SoundPoolListenerThread() {
2034 super("SoundPoolListenerThread");
2035 }
2036
2037 @Override
2038 public void run() {
2039
2040 Looper.prepare();
2041 mSoundPoolLooper = Looper.myLooper();
2042
2043 synchronized (mSoundEffectsLock) {
2044 if (mSoundPool != null) {
2045 mSoundPoolCallBack = new SoundPoolCallback();
2046 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2047 }
2048 mSoundEffectsLock.notify();
2049 }
2050 Looper.loop();
2051 }
2052 }
2053
2054 private final class SoundPoolCallback implements
2055 android.media.SoundPool.OnLoadCompleteListener {
2056
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002057 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2058 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002059
2060 public int status() {
2061 return mStatus;
2062 }
2063
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002064 public void setSamples(int[] samples) {
2065 for (int i = 0; i < samples.length; i++) {
2066 // do not wait ack for samples rejected upfront by SoundPool
2067 if (samples[i] > 0) {
2068 mSamples.add(samples[i]);
2069 }
2070 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002071 }
2072
2073 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2074 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002075 int i = mSamples.indexOf(sampleId);
2076 if (i >= 0) {
2077 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002078 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002079 if ((status != 0) || mSamples. isEmpty()) {
2080 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002081 mSoundEffectsLock.notify();
2082 }
2083 }
2084 }
2085 }
2086
Eric Laurent4050c932009-07-08 02:52:14 -07002087 /** @see AudioManager#reloadAudioSettings() */
2088 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002089 readAudioSettings(false /*userSwitch*/);
2090 }
2091
2092 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002093 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2094 readPersistedSettings();
2095
2096 // restore volume settings
2097 int numStreamTypes = AudioSystem.getNumStreamTypes();
2098 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2099 VolumeStreamState streamState = mStreamStates[streamType];
2100
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002101 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2102 continue;
2103 }
2104
Eric Laurent3172d5e2012-05-09 11:38:16 -07002105 synchronized (streamState) {
2106 streamState.readSettings();
Eric Laurenta553c252009-07-17 12:17:14 -07002107
Eric Laurent3172d5e2012-05-09 11:38:16 -07002108 // unmute stream that was muted but is not affect by mute anymore
Eric Laurent42b041e2013-03-29 11:36:03 -07002109 if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002110 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002111 int size = streamState.mDeathHandlers.size();
2112 for (int i = 0; i < size; i++) {
2113 streamState.mDeathHandlers.get(i).mMuteCount = 1;
2114 streamState.mDeathHandlers.get(i).mute(false);
2115 }
Eric Laurent4050c932009-07-08 02:52:14 -07002116 }
Eric Laurent4050c932009-07-08 02:52:14 -07002117 }
2118 }
2119
Eric Laurent33902db2012-10-07 16:15:07 -07002120 // apply new ringer mode before checking volume for alias streams so that streams
2121 // muted by ringer mode have the correct volume
2122 setRingerModeInt(getRingerMode(), false);
2123
Eric Laurent212532b2014-07-21 15:43:18 -07002124 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002125 checkAllAliasStreamVolumes();
2126
Eric Laurentd640bd32012-09-28 18:01:48 -07002127 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002128 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2129 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2130 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002131 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002132 enforceSafeMediaVolume();
2133 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002134 }
Eric Laurent4050c932009-07-08 02:52:14 -07002135 }
2136
Dianne Hackborn961cae92013-03-20 14:59:43 -07002137 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002138 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002139 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2140 return;
2141 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002142
2143 if (on) {
2144 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2145 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2146 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2147 }
2148 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2149 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2150 mForcedUseForComm = AudioSystem.FORCE_NONE;
2151 }
Eric Laurentfa640152011-03-12 15:59:51 -08002152
Eric Laurentafbb0472011-12-15 09:04:23 -08002153 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002154 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002155 }
2156
2157 /** @see AudioManager#isSpeakerphoneOn() */
2158 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002159 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002160 }
2161
Dianne Hackborn961cae92013-03-20 14:59:43 -07002162 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002163 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002164 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2165 return;
2166 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002167
2168 if (on) {
2169 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2170 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2171 mForcedUseForComm = AudioSystem.FORCE_NONE;
2172 }
Eric Laurentfa640152011-03-12 15:59:51 -08002173
Eric Laurentafbb0472011-12-15 09:04:23 -08002174 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002175 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002176 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002177 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002178 }
2179
2180 /** @see AudioManager#isBluetoothScoOn() */
2181 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002182 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002183 }
2184
Dianne Hackborn961cae92013-03-20 14:59:43 -07002185 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002186 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002187 synchronized (mBluetoothA2dpEnabledLock) {
2188 mBluetoothA2dpEnabled = on;
2189 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2190 AudioSystem.FOR_MEDIA,
2191 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2192 null, 0);
2193 }
Eric Laurent78472112012-05-21 08:57:21 -07002194 }
2195
2196 /** @see AudioManager#isBluetoothA2dpOn() */
2197 public boolean isBluetoothA2dpOn() {
2198 synchronized (mBluetoothA2dpEnabledLock) {
2199 return mBluetoothA2dpEnabled;
2200 }
2201 }
2202
Eric Laurent3def1ee2010-03-17 23:26:26 -07002203 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002204 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2205 int scoAudioMode =
2206 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002207 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002208 startBluetoothScoInt(cb, scoAudioMode);
2209 }
2210
2211 /** @see AudioManager#startBluetoothScoVirtualCall() */
2212 public void startBluetoothScoVirtualCall(IBinder cb) {
2213 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2214 }
2215
2216 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002217 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002218 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002219 return;
2220 }
Eric Laurent854938a2011-02-22 12:05:20 -08002221 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002222 // The calling identity must be cleared before calling ScoClient.incCount().
2223 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2224 // and this must be done on behalf of system server to make sure permissions are granted.
2225 // The caller identity must be cleared after getScoClient() because it is needed if a new
2226 // client is created.
2227 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002228 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002229 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002230 }
2231
2232 /** @see AudioManager#stopBluetoothSco() */
2233 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002234 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002235 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002236 return;
2237 }
Eric Laurent854938a2011-02-22 12:05:20 -08002238 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002239 // The calling identity must be cleared before calling ScoClient.decCount().
2240 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2241 // and this must be done on behalf of system server to make sure permissions are granted.
2242 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002243 if (client != null) {
2244 client.decCount();
2245 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002246 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002247 }
2248
Eric Laurent78472112012-05-21 08:57:21 -07002249
Eric Laurent3def1ee2010-03-17 23:26:26 -07002250 private class ScoClient implements IBinder.DeathRecipient {
2251 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002252 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002253 private int mStartcount; // number of SCO connections started by this client
2254
2255 ScoClient(IBinder cb) {
2256 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002257 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002258 mStartcount = 0;
2259 }
2260
2261 public void binderDied() {
2262 synchronized(mScoClients) {
2263 Log.w(TAG, "SCO client died");
2264 int index = mScoClients.indexOf(this);
2265 if (index < 0) {
2266 Log.w(TAG, "unregistered SCO client died");
2267 } else {
2268 clearCount(true);
2269 mScoClients.remove(this);
2270 }
2271 }
2272 }
2273
Eric Laurent83900752014-05-15 15:14:22 -07002274 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002275 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002276 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002277 if (mStartcount == 0) {
2278 try {
2279 mCb.linkToDeath(this, 0);
2280 } catch (RemoteException e) {
2281 // client has already died!
2282 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2283 }
2284 }
2285 mStartcount++;
2286 }
2287 }
2288
2289 public void decCount() {
2290 synchronized(mScoClients) {
2291 if (mStartcount == 0) {
2292 Log.w(TAG, "ScoClient.decCount() already 0");
2293 } else {
2294 mStartcount--;
2295 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002296 try {
2297 mCb.unlinkToDeath(this, 0);
2298 } catch (NoSuchElementException e) {
2299 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2300 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002301 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002302 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002303 }
2304 }
2305 }
2306
2307 public void clearCount(boolean stopSco) {
2308 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002309 if (mStartcount != 0) {
2310 try {
2311 mCb.unlinkToDeath(this, 0);
2312 } catch (NoSuchElementException e) {
2313 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2314 }
2315 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002316 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002317 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002318 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002319 }
2320 }
2321 }
2322
2323 public int getCount() {
2324 return mStartcount;
2325 }
2326
2327 public IBinder getBinder() {
2328 return mCb;
2329 }
2330
Eric Laurentd7454be2011-09-14 08:45:58 -07002331 public int getPid() {
2332 return mCreatorPid;
2333 }
2334
Eric Laurent3def1ee2010-03-17 23:26:26 -07002335 public int totalCount() {
2336 synchronized(mScoClients) {
2337 int count = 0;
2338 int size = mScoClients.size();
2339 for (int i = 0; i < size; i++) {
2340 count += mScoClients.get(i).getCount();
2341 }
2342 return count;
2343 }
2344 }
2345
Eric Laurent83900752014-05-15 15:14:22 -07002346 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002347 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002348 if (totalCount() == 0) {
2349 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2350 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2351 // the connection.
2352 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2353 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002354 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002355 synchronized(mSetModeDeathHandlers) {
2356 if ((mSetModeDeathHandlers.isEmpty() ||
2357 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2358 (mScoAudioState == SCO_STATE_INACTIVE ||
2359 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2360 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002361 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002362 if (scoAudioMode == SCO_MODE_UNDEFINED) {
2363 mScoAudioMode = new Integer(Settings.Global.getInt(
2364 mContentResolver,
2365 "bluetooth_sco_channel_"+
2366 mBluetoothHeadsetDevice.getAddress(),
2367 SCO_MODE_VIRTUAL_CALL));
2368 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2369 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2370 }
2371 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002372 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002373 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002374 if (mScoAudioMode == SCO_MODE_RAW) {
2375 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002376 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002377 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2378 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002379 } else if (mScoAudioMode == SCO_MODE_VR) {
2380 status = mBluetoothHeadset.startVoiceRecognition(
2381 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002382 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002383
Eric Laurentc18c9132013-04-12 17:24:56 -07002384 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002385 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2386 } else {
2387 broadcastScoConnectionState(
2388 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2389 }
2390 } else if (getBluetoothHeadset()) {
2391 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002392 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002393 } else {
2394 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2395 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002396 }
2397 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002398 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002399 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002400 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002401 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002402 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2403 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2404 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002405 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002406 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002407 if (mScoAudioMode == SCO_MODE_RAW) {
2408 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002409 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002410 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2411 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002412 } else if (mScoAudioMode == SCO_MODE_VR) {
2413 status = mBluetoothHeadset.stopVoiceRecognition(
2414 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002415 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002416
Eric Laurentc18c9132013-04-12 17:24:56 -07002417 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002418 mScoAudioState = SCO_STATE_INACTIVE;
2419 broadcastScoConnectionState(
2420 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2421 }
2422 } else if (getBluetoothHeadset()) {
2423 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2424 }
2425 } else {
2426 mScoAudioState = SCO_STATE_INACTIVE;
2427 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2428 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002429 }
2430 }
2431 }
2432 }
2433
Eric Laurent62ef7672010-11-24 10:58:32 -08002434 private void checkScoAudioState() {
2435 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002436 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002437 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2438 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2439 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2440 }
2441 }
2442
Eric Laurent854938a2011-02-22 12:05:20 -08002443 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002444 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002445 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002446 int size = mScoClients.size();
2447 for (int i = 0; i < size; i++) {
2448 client = mScoClients.get(i);
2449 if (client.getBinder() == cb)
2450 return client;
2451 }
Eric Laurent854938a2011-02-22 12:05:20 -08002452 if (create) {
2453 client = new ScoClient(cb);
2454 mScoClients.add(client);
2455 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002456 return client;
2457 }
2458 }
2459
Eric Laurentd7454be2011-09-14 08:45:58 -07002460 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002461 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002462 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002463 int size = mScoClients.size();
2464 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002465 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002466 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002467 cl.clearCount(stopSco);
2468 } else {
2469 savedClient = cl;
2470 }
2471 }
2472 mScoClients.clear();
2473 if (savedClient != null) {
2474 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002475 }
2476 }
2477 }
2478
Eric Laurentdc03c612011-04-01 10:59:41 -07002479 private boolean getBluetoothHeadset() {
2480 boolean result = false;
2481 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2482 if (adapter != null) {
2483 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2484 BluetoothProfile.HEADSET);
2485 }
2486 // If we could not get a bluetooth headset proxy, send a failure message
2487 // without delay to reset the SCO audio state and clear SCO clients.
2488 // If we could get a proxy, send a delayed failure message that will reset our state
2489 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002490 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002491 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2492 return result;
2493 }
2494
Eric Laurentd7454be2011-09-14 08:45:58 -07002495 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002496 synchronized(mScoClients) {
2497 checkScoAudioState();
2498 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2499 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2500 if (mBluetoothHeadsetDevice != null) {
2501 if (mBluetoothHeadset != null) {
2502 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002503 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002504 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002505 SENDMSG_REPLACE, 0, 0, null, 0);
2506 }
2507 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2508 getBluetoothHeadset()) {
2509 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2510 }
2511 }
2512 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002513 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002514 }
2515 }
2516 }
2517
2518 private void resetBluetoothSco() {
2519 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002520 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002521 mScoAudioState = SCO_STATE_INACTIVE;
2522 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2523 }
2524 }
2525
2526 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002527 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2528 SENDMSG_QUEUE, state, 0, null, 0);
2529 }
2530
2531 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002532 if (state != mScoConnectionState) {
2533 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2534 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2535 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2536 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002537 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002538 mScoConnectionState = state;
2539 }
2540 }
2541
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002542 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2543 new BluetoothProfile.ServiceListener() {
2544 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002545 BluetoothDevice btDevice;
2546 List<BluetoothDevice> deviceList;
2547 switch(profile) {
2548 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002549 synchronized (mA2dpAvrcpLock) {
2550 mA2dp = (BluetoothA2dp) proxy;
2551 deviceList = mA2dp.getConnectedDevices();
2552 if (deviceList.size() > 0) {
2553 btDevice = deviceList.get(0);
2554 synchronized (mConnectedDevices) {
2555 int state = mA2dp.getConnectionState(btDevice);
2556 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002557 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2558 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002559 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002560 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002561 state,
2562 0,
2563 btDevice,
2564 delay);
2565 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002566 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002567 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002568 break;
2569
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002570 case BluetoothProfile.A2DP_SINK:
2571 deviceList = proxy.getConnectedDevices();
2572 if (deviceList.size() > 0) {
2573 btDevice = deviceList.get(0);
2574 synchronized (mConnectedDevices) {
2575 int state = proxy.getConnectionState(btDevice);
2576 queueMsgUnderWakeLock(mAudioHandler,
2577 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2578 state,
2579 0,
2580 btDevice,
2581 0 /* delay */);
2582 }
2583 }
2584 break;
2585
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002586 case BluetoothProfile.HEADSET:
2587 synchronized (mScoClients) {
2588 // Discard timeout message
2589 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2590 mBluetoothHeadset = (BluetoothHeadset) proxy;
2591 deviceList = mBluetoothHeadset.getConnectedDevices();
2592 if (deviceList.size() > 0) {
2593 mBluetoothHeadsetDevice = deviceList.get(0);
2594 } else {
2595 mBluetoothHeadsetDevice = null;
2596 }
2597 // Refresh SCO audio state
2598 checkScoAudioState();
2599 // Continue pending action if any
2600 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2601 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2602 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2603 boolean status = false;
2604 if (mBluetoothHeadsetDevice != null) {
2605 switch (mScoAudioState) {
2606 case SCO_STATE_ACTIVATE_REQ:
2607 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002608 if (mScoAudioMode == SCO_MODE_RAW) {
2609 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002610 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002611 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2612 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002613 } else if (mScoAudioMode == SCO_MODE_VR) {
2614 status = mBluetoothHeadset.startVoiceRecognition(
2615 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002616 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002617 break;
2618 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002619 if (mScoAudioMode == SCO_MODE_RAW) {
2620 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002621 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002622 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2623 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002624 } else if (mScoAudioMode == SCO_MODE_VR) {
2625 status = mBluetoothHeadset.stopVoiceRecognition(
2626 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002627 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002628 break;
2629 case SCO_STATE_DEACTIVATE_EXT_REQ:
2630 status = mBluetoothHeadset.stopVoiceRecognition(
2631 mBluetoothHeadsetDevice);
2632 }
2633 }
2634 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002635 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002636 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002637 }
2638 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002639 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002640 break;
2641
2642 default:
2643 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002644 }
2645 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002646 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002647 switch(profile) {
2648 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002649 synchronized (mA2dpAvrcpLock) {
2650 mA2dp = null;
2651 synchronized (mConnectedDevices) {
2652 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2653 makeA2dpDeviceUnavailableNow(
2654 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2655 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002656 }
2657 }
2658 break;
2659
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002660 case BluetoothProfile.A2DP_SINK:
2661 synchronized (mConnectedDevices) {
2662 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2663 makeA2dpSrcUnavailable(
2664 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2665 }
2666 }
2667 break;
2668
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002669 case BluetoothProfile.HEADSET:
2670 synchronized (mScoClients) {
2671 mBluetoothHeadset = null;
2672 }
2673 break;
2674
2675 default:
2676 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002677 }
2678 }
2679 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002680
Eric Laurentc34dcc12012-09-10 13:51:52 -07002681 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002682 synchronized (mSafeMediaVolumeState) {
2683 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002684 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2685
2686 if ((device & mSafeMediaVolumeDevices) != 0) {
2687 sendMsg(mAudioHandler,
2688 MSG_CHECK_MUSIC_ACTIVE,
2689 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002690 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002691 0,
2692 null,
2693 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002694 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002695 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2696 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002697 // Approximate cumulative active music time
2698 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2699 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2700 setSafeMediaVolumeEnabled(true);
2701 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002702 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002703 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002704 }
2705 }
2706 }
2707 }
2708 }
2709
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002710 private void saveMusicActiveMs() {
2711 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2712 }
2713
Eric Laurentd640bd32012-09-28 18:01:48 -07002714 private void onConfigureSafeVolume(boolean force) {
2715 synchronized (mSafeMediaVolumeState) {
2716 int mcc = mContext.getResources().getConfiguration().mcc;
2717 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2718 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2719 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04002720 boolean safeMediaVolumeEnabled =
2721 SystemProperties.getBoolean("audio.safemedia.force", false)
2722 || mContext.getResources().getBoolean(
2723 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002724
2725 // The persisted state is either "disabled" or "active": this is the state applied
2726 // next time we boot and cannot be "inactive"
2727 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002728 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002729 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2730 // The state can already be "inactive" here if the user has forced it before
2731 // the 30 seconds timeout for forced configuration. In this case we don't reset
2732 // it to "active".
2733 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002734 if (mMusicActiveMs == 0) {
2735 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2736 enforceSafeMediaVolume();
2737 } else {
2738 // We have existing playback time recorded, already confirmed.
2739 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2740 }
Eric Laurent05274f32012-11-29 12:48:18 -08002741 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002742 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002743 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002744 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2745 }
2746 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002747 sendMsg(mAudioHandler,
2748 MSG_PERSIST_SAFE_VOLUME_STATE,
2749 SENDMSG_QUEUE,
2750 persistedState,
2751 0,
2752 null,
2753 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002754 }
2755 }
2756 }
2757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002758 ///////////////////////////////////////////////////////////////////////////
2759 // Internal methods
2760 ///////////////////////////////////////////////////////////////////////////
2761
2762 /**
2763 * Checks if the adjustment should change ringer mode instead of just
2764 * adjusting volume. If so, this will set the proper ringer mode and volume
2765 * indices on the stream states.
2766 */
John Spurlocka11b4af2014-06-01 11:52:23 -04002767 private int checkForRingerModeChange(int oldIndex, int direction, int step) {
2768 int result = FLAG_ADJUST_VOLUME;
Glenn Kastenba195eb2011-12-13 09:30:40 -08002769 int ringerMode = getRingerMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002770
Eric Laurentbffc3d12012-05-07 17:43:49 -07002771 switch (ringerMode) {
2772 case RINGER_MODE_NORMAL:
2773 if (direction == AudioManager.ADJUST_LOWER) {
2774 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002775 // "step" is the delta in internal index units corresponding to a
2776 // change of 1 in UI index units.
2777 // Because of rounding when rescaling from one stream index range to its alias
2778 // index range, we cannot simply test oldIndex == step:
2779 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2780 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002781 ringerMode = RINGER_MODE_VIBRATE;
2782 }
2783 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002784 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002785 if ((oldIndex < step)
2786 && VOLUME_SETS_RINGER_MODE_SILENT
2787 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002788 ringerMode = RINGER_MODE_SILENT;
2789 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002791 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002792 break;
2793 case RINGER_MODE_VIBRATE:
2794 if (!mHasVibrator) {
2795 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2796 "but no vibrator is present");
2797 break;
2798 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002799 if ((direction == AudioManager.ADJUST_LOWER)) {
John Spurlock86005342014-05-23 11:58:00 -04002800 if (VOLUME_SETS_RINGER_MODE_SILENT
2801 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002802 ringerMode = RINGER_MODE_SILENT;
Amith Yamasanic696a532011-10-28 17:02:37 -07002803 }
2804 } else if (direction == AudioManager.ADJUST_RAISE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002805 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002806 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002807 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002808 break;
2809 case RINGER_MODE_SILENT:
Daniel Sandler6329bf72010-02-26 15:17:44 -05002810 if (direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002811 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2812 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002813 } else {
John Spurlocka11b4af2014-06-01 11:52:23 -04002814 if (mHasVibrator) {
2815 ringerMode = RINGER_MODE_VIBRATE;
2816 } else {
2817 ringerMode = RINGER_MODE_NORMAL;
2818 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002819 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05002820 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002821 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002822 break;
2823 default:
2824 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2825 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002826 }
2827
Eric Laurentbffc3d12012-05-07 17:43:49 -07002828 setRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829
Eric Laurent25101b02011-02-02 09:33:30 -08002830 mPrevVolDirection = direction;
2831
John Spurlocka11b4af2014-06-01 11:52:23 -04002832 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002833 }
2834
John Spurlock3346a802014-05-20 16:25:37 -04002835 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07002837 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002838 }
2839
Eric Laurent5b4e6542010-03-19 20:02:21 -07002840 private boolean isStreamMutedByRingerMode(int streamType) {
2841 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2842 }
2843
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002844 boolean updateRingerModeAffectedStreams() {
2845 int ringerModeAffectedStreams;
2846 // make sure settings for ringer mode are consistent with device type: non voice capable
2847 // devices (tablets) include media stream in silent mode whereas phones don't.
2848 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2849 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2850 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2851 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2852 UserHandle.USER_CURRENT);
2853
2854 // ringtone, notification and system streams are always affected by ringer mode
2855 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2856 (1 << AudioSystem.STREAM_NOTIFICATION)|
2857 (1 << AudioSystem.STREAM_SYSTEM);
2858
Eric Laurent212532b2014-07-21 15:43:18 -07002859 switch (mPlatformType) {
Eric Laurent212532b2014-07-21 15:43:18 -07002860 case PLATFORM_TELEVISION:
2861 ringerModeAffectedStreams = 0;
2862 break;
2863 default:
John Spurlock77e54d92014-08-11 12:16:24 -04002864 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07002865 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002866 }
Eric Laurent212532b2014-07-21 15:43:18 -07002867
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002868 synchronized (mCameraSoundForced) {
2869 if (mCameraSoundForced) {
2870 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2871 } else {
2872 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2873 }
2874 }
2875 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2876 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2877 } else {
2878 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2879 }
2880
2881 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2882 Settings.System.putIntForUser(mContentResolver,
2883 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2884 ringerModeAffectedStreams,
2885 UserHandle.USER_CURRENT);
2886 mRingerModeAffectedStreams = ringerModeAffectedStreams;
2887 return true;
2888 }
2889 return false;
2890 }
2891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002892 public boolean isStreamAffectedByMute(int streamType) {
2893 return (mMuteAffectedStreams & (1 << streamType)) != 0;
2894 }
2895
2896 private void ensureValidDirection(int direction) {
2897 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2898 throw new IllegalArgumentException("Bad direction " + direction);
2899 }
2900 }
2901
Lei Zhang6c798972012-03-02 11:40:12 -08002902 private void ensureValidSteps(int steps) {
2903 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2904 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2905 }
2906 }
2907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 private void ensureValidStreamType(int streamType) {
2909 if (streamType < 0 || streamType >= mStreamStates.length) {
2910 throw new IllegalArgumentException("Bad stream type " + streamType);
2911 }
2912 }
2913
Eric Laurent6d517662012-04-23 18:42:39 -07002914 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07002915 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916
Santos Cordon9eb45932014-06-27 12:28:43 -07002917 TelecommManager telecommManager =
2918 (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
Nancy Chen0eb1e402014-08-21 22:52:29 -07002919 IsInCall = telecommManager.isInCall();
Santos Cordon9eb45932014-06-27 12:28:43 -07002920
Nancy Chen0eb1e402014-08-21 22:52:29 -07002921 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07002922 }
Eric Laurent25101b02011-02-02 09:33:30 -08002923
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002924 /**
2925 * For code clarity for getActiveStreamType(int)
2926 * @param delay_ms max time since last STREAM_MUSIC activity to consider
2927 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2928 * in the last "delay_ms" ms.
2929 */
2930 private boolean isAfMusicActiveRecently(int delay_ms) {
2931 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2932 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2933 }
2934
Eric Laurent6d517662012-04-23 18:42:39 -07002935 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07002936 switch (mPlatformType) {
2937 case PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07002938 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002939 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2940 == AudioSystem.FORCE_BT_SCO) {
2941 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2942 return AudioSystem.STREAM_BLUETOOTH_SCO;
2943 } else {
2944 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2945 return AudioSystem.STREAM_VOICE_CALL;
2946 }
Eric Laurent25101b02011-02-02 09:33:30 -08002947 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002948 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002949 if (DEBUG_VOL)
2950 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2951 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002952 } else {
2953 if (DEBUG_VOL)
2954 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2955 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002956 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002957 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002958 if (DEBUG_VOL)
2959 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2960 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08002961 }
Eric Laurent212532b2014-07-21 15:43:18 -07002962 break;
2963 case PLATFORM_TELEVISION:
2964 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07002965 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07002966 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07002967 }
2968 break;
2969 default:
Eric Laurent6d517662012-04-23 18:42:39 -07002970 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002971 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2972 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002973 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08002974 return AudioSystem.STREAM_BLUETOOTH_SCO;
2975 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002976 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08002977 return AudioSystem.STREAM_VOICE_CALL;
2978 }
2979 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Eric Laurent9903e262012-09-21 18:10:32 -07002980 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002981 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Eric Laurent9903e262012-09-21 18:10:32 -07002982 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002983 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08002984 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002985 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002986 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2987 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2988 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002989 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04002990 if (DEBUG_VOL) Log.v(TAG,
2991 "getActiveStreamType: using STREAM_NOTIFICATION as default");
2992 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002993 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08002994 }
Eric Laurent212532b2014-07-21 15:43:18 -07002995 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002996 }
Eric Laurent212532b2014-07-21 15:43:18 -07002997 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2998 + suggestedStreamType);
2999 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003000 }
3001
Glenn Kastenba195eb2011-12-13 09:30:40 -08003002 private void broadcastRingerMode(int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 // Send sticky broadcast
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003004 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003005 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003006 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3007 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003008 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009 }
3010
3011 private void broadcastVibrateSetting(int vibrateType) {
3012 // Send broadcast
3013 if (ActivityManagerNative.isSystemReady()) {
3014 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3015 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3016 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003017 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018 }
3019 }
3020
3021 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003022 /**
3023 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3024 * Note that the wake lock needs to be released after the message has been handled.
3025 */
3026 private void queueMsgUnderWakeLock(Handler handler, int msg,
3027 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003028 final long ident = Binder.clearCallingIdentity();
3029 // Always acquire the wake lock as AudioService because it is released by the
3030 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003031 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003032 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003033 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035
Eric Laurentafbb0472011-12-15 09:04:23 -08003036 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003037 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003038
3039 if (existingMsgPolicy == SENDMSG_REPLACE) {
3040 handler.removeMessages(msg);
3041 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3042 return;
3043 }
3044
Eric Laurentafbb0472011-12-15 09:04:23 -08003045 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 }
3047
3048 boolean checkAudioSettingsPermission(String method) {
3049 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
3050 == PackageManager.PERMISSION_GRANTED) {
3051 return true;
3052 }
3053 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3054 + Binder.getCallingPid()
3055 + ", uid=" + Binder.getCallingUid();
3056 Log.w(TAG, msg);
3057 return false;
3058 }
3059
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003060 private int getDeviceForStream(int stream) {
3061 int device = AudioSystem.getDevicesForStream(stream);
3062 if ((device & (device - 1)) != 0) {
3063 // Multiple device selection is either:
3064 // - speaker + one other device: give priority to speaker in this case.
3065 // - one A2DP device + another device: happens with duplicated output. In this case
3066 // retain the device on the A2DP output as the other must not correspond to an active
3067 // selection if not the speaker.
3068 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3069 device = AudioSystem.DEVICE_OUT_SPEAKER;
3070 } else {
3071 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3072 }
3073 }
3074 return device;
3075 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003077 public void setWiredDeviceConnectionState(int device, int state, String name) {
3078 synchronized (mConnectedDevices) {
3079 int delay = checkSendBecomingNoisyIntent(device, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003080 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003081 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003082 device,
3083 state,
3084 name,
3085 delay);
3086 }
3087 }
3088
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003089 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003090 {
3091 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003092 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3093 throw new IllegalArgumentException("invalid profile " + profile);
3094 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003095 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003096 if (profile == BluetoothProfile.A2DP) {
3097 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3098 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3099 } else {
3100 delay = 0;
3101 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003102 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003103 (profile == BluetoothProfile.A2DP ?
3104 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003105 state,
3106 0,
3107 device,
3108 delay);
3109 }
3110 return delay;
3111 }
3112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003113 ///////////////////////////////////////////////////////////////////////////
3114 // Inner classes
3115 ///////////////////////////////////////////////////////////////////////////
3116
3117 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118 private final int mStreamType;
3119
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003120 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003121 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003122 private final ConcurrentHashMap<Integer, Integer> mIndex =
3123 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003124 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003125
Eric Laurenta553c252009-07-17 12:17:14 -07003126 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003127
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003128 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129
3130 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003131 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003132 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3133 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003134
Eric Laurent33902db2012-10-07 16:15:07 -07003135 // mDeathHandlers must be created before calling readSettings()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003136 mDeathHandlers = new ArrayList<VolumeDeathHandler>();
Eric Laurent33902db2012-10-07 16:15:07 -07003137
3138 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003139 }
3140
Eric Laurent42b041e2013-03-29 11:36:03 -07003141 public String getSettingNameForDevice(int device) {
3142 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003143 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003144 if (suffix.isEmpty()) {
3145 return name;
3146 }
3147 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003148 }
3149
Eric Laurentfdbee862014-05-12 15:26:12 -07003150 public void readSettings() {
3151 synchronized (VolumeStreamState.class) {
3152 // force maximum volume on all streams if fixed volume property is set
3153 if (mUseFixedVolume) {
3154 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3155 return;
3156 }
3157 // do not read system stream volume from settings: this stream is always aliased
3158 // to another stream type and its volume is never persisted. Values in settings can
3159 // only be stale values
3160 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3161 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
3162 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
3163 synchronized (mCameraSoundForced) {
3164 if (mCameraSoundForced) {
3165 index = mIndexMax;
3166 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003167 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003168 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3169 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003170 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003171
Eric Laurentfdbee862014-05-12 15:26:12 -07003172 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3173
3174 for (int i = 0; remainingDevices != 0; i++) {
3175 int device = (1 << i);
3176 if ((device & remainingDevices) == 0) {
3177 continue;
3178 }
3179 remainingDevices &= ~device;
3180
3181 // retrieve current volume for device
3182 String name = getSettingNameForDevice(device);
3183 // if no volume stored for current stream and device, use default volume if default
3184 // device, continue otherwise
3185 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3186 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3187 int index = Settings.System.getIntForUser(
3188 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3189 if (index == -1) {
3190 continue;
3191 }
3192
Eric Laurent212532b2014-07-21 15:43:18 -07003193 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003194 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 }
3197
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003198 public void applyDeviceVolume(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003199 int index;
3200 if (isMuted()) {
3201 index = 0;
Eric Laurentcd772d02013-10-30 18:31:07 -07003202 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003203 mAvrcpAbsVolSupported) {
3204 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003205 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003206 index = (getIndex(device) + 5)/10;
3207 }
3208 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210
Eric Laurentfdbee862014-05-12 15:26:12 -07003211 public void applyAllVolumes() {
3212 synchronized (VolumeStreamState.class) {
3213 // apply default volume first: by convention this will reset all
3214 // devices volumes in audio policy manager to the supplied value
3215 int index;
3216 if (isMuted()) {
3217 index = 0;
3218 } else {
3219 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3220 }
3221 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3222 // then apply device specific volumes
3223 Set set = mIndex.entrySet();
3224 Iterator i = set.iterator();
3225 while (i.hasNext()) {
3226 Map.Entry entry = (Map.Entry)i.next();
3227 int device = ((Integer)entry.getKey()).intValue();
3228 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3229 if (isMuted()) {
3230 index = 0;
3231 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3232 mAvrcpAbsVolSupported) {
3233 index = (mIndexMax + 5)/10;
3234 } else {
3235 index = ((Integer)entry.getValue() + 5)/10;
3236 }
3237 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003238 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003239 }
3240 }
3241 }
3242
3243 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003244 return setIndex(getIndex(device) + deltaIndex,
3245 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003246 }
3247
Eric Laurentfdbee862014-05-12 15:26:12 -07003248 public boolean setIndex(int index, int device) {
3249 synchronized (VolumeStreamState.class) {
3250 int oldIndex = getIndex(device);
3251 index = getValidIndex(index);
3252 synchronized (mCameraSoundForced) {
3253 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3254 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003255 }
3256 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003257 mIndex.put(device, index);
3258
3259 if (oldIndex != index) {
3260 // Apply change to all streams using this one as alias
3261 // if changing volume of current device, also change volume of current
3262 // device on aliased stream
3263 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3264 int numStreamTypes = AudioSystem.getNumStreamTypes();
3265 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3266 if (streamType != mStreamType &&
3267 mStreamVolumeAlias[streamType] == mStreamType) {
3268 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3269 mStreamStates[streamType].setIndex(scaledIndex,
3270 device);
3271 if (currentDevice) {
3272 mStreamStates[streamType].setIndex(scaledIndex,
3273 getDeviceForStream(streamType));
3274 }
3275 }
3276 }
3277 return true;
3278 } else {
3279 return false;
3280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 }
3282 }
3283
Eric Laurentfdbee862014-05-12 15:26:12 -07003284 public int getIndex(int device) {
3285 synchronized (VolumeStreamState.class) {
3286 Integer index = mIndex.get(device);
3287 if (index == null) {
3288 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3289 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3290 }
3291 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003292 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003293 }
3294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003296 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 }
3298
Eric Laurentfdbee862014-05-12 15:26:12 -07003299 public void setAllIndexes(VolumeStreamState srcStream) {
3300 synchronized (VolumeStreamState.class) {
3301 int srcStreamType = srcStream.getStreamType();
3302 // apply default device volume from source stream to all devices first in case
3303 // some devices are present in this stream state but not in source stream state
3304 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003305 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003306 Set set = mIndex.entrySet();
3307 Iterator i = set.iterator();
3308 while (i.hasNext()) {
3309 Map.Entry entry = (Map.Entry)i.next();
3310 entry.setValue(index);
3311 }
3312 // Now apply actual volume for devices in source stream state
3313 set = srcStream.mIndex.entrySet();
3314 i = set.iterator();
3315 while (i.hasNext()) {
3316 Map.Entry entry = (Map.Entry)i.next();
3317 int device = ((Integer)entry.getKey()).intValue();
3318 index = ((Integer)entry.getValue()).intValue();
3319 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003320
Eric Laurentfdbee862014-05-12 15:26:12 -07003321 setIndex(index, device);
3322 }
Eric Laurent6d517662012-04-23 18:42:39 -07003323 }
3324 }
3325
Eric Laurentfdbee862014-05-12 15:26:12 -07003326 public void setAllIndexesToMax() {
3327 synchronized (VolumeStreamState.class) {
3328 Set set = mIndex.entrySet();
3329 Iterator i = set.iterator();
3330 while (i.hasNext()) {
3331 Map.Entry entry = (Map.Entry)i.next();
3332 entry.setValue(mIndexMax);
3333 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003334 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003335 }
3336
Eric Laurentfdbee862014-05-12 15:26:12 -07003337 public void mute(IBinder cb, boolean state) {
3338 synchronized (VolumeStreamState.class) {
3339 VolumeDeathHandler handler = getDeathHandler(cb, state);
3340 if (handler == null) {
3341 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3342 return;
3343 }
3344 handler.mute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 }
3347
Eric Laurent6d517662012-04-23 18:42:39 -07003348 public int getStreamType() {
3349 return mStreamType;
3350 }
3351
Eric Laurent212532b2014-07-21 15:43:18 -07003352 public void checkFixedVolumeDevices() {
3353 synchronized (VolumeStreamState.class) {
3354 // ignore settings for fixed volume devices: volume should always be at max or 0
3355 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3356 Set set = mIndex.entrySet();
3357 Iterator i = set.iterator();
3358 while (i.hasNext()) {
3359 Map.Entry entry = (Map.Entry)i.next();
3360 int device = ((Integer)entry.getKey()).intValue();
3361 int index = ((Integer)entry.getValue()).intValue();
3362 if (((device & mFixedVolumeDevices) != 0) && index != 0) {
3363 entry.setValue(mIndexMax);
3364 }
3365 applyDeviceVolume(device);
3366 }
3367 }
3368 }
3369 }
3370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371 private int getValidIndex(int index) {
3372 if (index < 0) {
3373 return 0;
Eric Laurent83a017b2013-03-19 18:15:31 -07003374 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003375 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 }
3377
3378 return index;
3379 }
3380
3381 private class VolumeDeathHandler implements IBinder.DeathRecipient {
3382 private IBinder mICallback; // To be notified of client's death
3383 private int mMuteCount; // Number of active mutes for this client
3384
3385 VolumeDeathHandler(IBinder cb) {
3386 mICallback = cb;
3387 }
3388
Eric Laurent3172d5e2012-05-09 11:38:16 -07003389 // must be called while synchronized on parent VolumeStreamState
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003390 public void mute(boolean state) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003391 boolean updateVolume = false;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003392 if (state) {
3393 if (mMuteCount == 0) {
3394 // Register for client death notification
3395 try {
3396 // mICallback can be 0 if muted by AudioService
3397 if (mICallback != null) {
3398 mICallback.linkToDeath(this, 0);
3399 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003400 VolumeStreamState.this.mDeathHandlers.add(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003401 // If the stream is not yet muted by any client, set level to 0
Eric Laurent42b041e2013-03-29 11:36:03 -07003402 if (!VolumeStreamState.this.isMuted()) {
3403 updateVolume = true;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003404 }
3405 } catch (RemoteException e) {
3406 // Client has died!
3407 binderDied();
3408 return;
3409 }
3410 } else {
3411 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3412 }
3413 mMuteCount++;
3414 } else {
3415 if (mMuteCount == 0) {
3416 Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3417 } else {
3418 mMuteCount--;
3419 if (mMuteCount == 0) {
3420 // Unregister from client death notification
Eric Laurent42b041e2013-03-29 11:36:03 -07003421 VolumeStreamState.this.mDeathHandlers.remove(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003422 // mICallback can be 0 if muted by AudioService
3423 if (mICallback != null) {
3424 mICallback.unlinkToDeath(this, 0);
3425 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003426 if (!VolumeStreamState.this.isMuted()) {
3427 updateVolume = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 }
3429 }
3430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003432 if (updateVolume) {
3433 sendMsg(mAudioHandler,
3434 MSG_SET_ALL_VOLUMES,
3435 SENDMSG_QUEUE,
3436 0,
3437 0,
3438 VolumeStreamState.this, 0);
3439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 }
3441
3442 public void binderDied() {
3443 Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3444 if (mMuteCount != 0) {
3445 // Reset all active mute requests from this client.
3446 mMuteCount = 1;
3447 mute(false);
3448 }
3449 }
3450 }
3451
Eric Laurent3172d5e2012-05-09 11:38:16 -07003452 private synchronized int muteCount() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453 int count = 0;
3454 int size = mDeathHandlers.size();
3455 for (int i = 0; i < size; i++) {
3456 count += mDeathHandlers.get(i).mMuteCount;
3457 }
3458 return count;
3459 }
3460
Eric Laurent42b041e2013-03-29 11:36:03 -07003461 private synchronized boolean isMuted() {
3462 return muteCount() != 0;
3463 }
3464
Eric Laurent3172d5e2012-05-09 11:38:16 -07003465 // only called by mute() which is already synchronized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003467 VolumeDeathHandler handler;
3468 int size = mDeathHandlers.size();
3469 for (int i = 0; i < size; i++) {
3470 handler = mDeathHandlers.get(i);
3471 if (cb == handler.mICallback) {
3472 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 }
Eric Laurent3172d5e2012-05-09 11:38:16 -07003475 // If this is the first mute request for this client, create a new
3476 // client death handler. Otherwise, it is an out of sequence unmute request.
3477 if (state) {
3478 handler = new VolumeDeathHandler(cb);
3479 } else {
3480 Log.w(TAG, "stream was not muted by this client");
3481 handler = null;
3482 }
3483 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003485
3486 private void dump(PrintWriter pw) {
Eric Laurentdd45d012012-10-08 09:04:34 -07003487 pw.print(" Mute count: ");
3488 pw.println(muteCount());
John Spurlock2b29bc42014-08-26 16:40:35 -04003489 pw.print(" Max: ");
3490 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003491 pw.print(" Current: ");
3492 Set set = mIndex.entrySet();
3493 Iterator i = set.iterator();
3494 while (i.hasNext()) {
3495 Map.Entry entry = (Map.Entry)i.next();
John Spurlock2b29bc42014-08-26 16:40:35 -04003496 final int device = (Integer) entry.getKey();
3497 pw.print(Integer.toHexString(device));
3498 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3499 : AudioSystem.getOutputDeviceName(device);
3500 if (!deviceName.isEmpty()) {
3501 pw.print(" (");
3502 pw.print(deviceName);
3503 pw.print(")");
3504 }
3505 pw.print(": ");
3506 final int index = (((Integer) entry.getValue()) + 5) / 10;
3507 pw.print(index);
3508 if (i.hasNext()) {
3509 pw.print(", ");
3510 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003511 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 }
3514
3515 /** Thread that handles native AudioSystem control. */
3516 private class AudioSystemThread extends Thread {
3517 AudioSystemThread() {
3518 super("AudioService");
3519 }
3520
3521 @Override
3522 public void run() {
3523 // Set this thread up so the handler will work on it
3524 Looper.prepare();
3525
3526 synchronized(AudioService.this) {
3527 mAudioHandler = new AudioHandler();
3528
3529 // Notify that the handler has been created
3530 AudioService.this.notify();
3531 }
3532
3533 // Listen for volume change requests that are set by VolumePanel
3534 Looper.loop();
3535 }
3536 }
3537
3538 /** Handles internal volume messages in separate volume thread. */
3539 private class AudioHandler extends Handler {
3540
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003541 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003543 // Apply volume
3544 streamState.applyDeviceVolume(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003545
3546 // Apply change to all streams using this one as alias
3547 int numStreamTypes = AudioSystem.getNumStreamTypes();
3548 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3549 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003550 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurentcd772d02013-10-30 18:31:07 -07003551 // Make sure volume is also maxed out on A2DP device for aliased stream
3552 // that may have a different device selected
3553 int streamDevice = getDeviceForStream(streamType);
3554 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3555 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3556 mStreamStates[streamType].applyDeviceVolume(device);
3557 }
3558 mStreamStates[streamType].applyDeviceVolume(streamDevice);
Eric Laurenta553c252009-07-17 12:17:14 -07003559 }
3560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561
3562 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003563 sendMsg(mAudioHandler,
3564 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003565 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003566 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003567 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003568 streamState,
3569 PERSIST_DELAY);
3570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 }
3572
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003573 private void setAllVolumes(VolumeStreamState streamState) {
3574
3575 // Apply volume
3576 streamState.applyAllVolumes();
3577
3578 // Apply change to all streams using this one as alias
3579 int numStreamTypes = AudioSystem.getNumStreamTypes();
3580 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3581 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003582 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003583 mStreamStates[streamType].applyAllVolumes();
3584 }
3585 }
3586 }
3587
Eric Laurent42b041e2013-03-29 11:36:03 -07003588 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003589 if (mUseFixedVolume) {
3590 return;
3591 }
Eric Laurent212532b2014-07-21 15:43:18 -07003592 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3593 return;
3594 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003595 System.putIntForUser(mContentResolver,
3596 streamState.getSettingNameForDevice(device),
3597 (streamState.getIndex(device) + 5)/ 10,
3598 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003599 }
3600
Glenn Kastenba195eb2011-12-13 09:30:40 -08003601 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003602 if (mUseFixedVolume) {
3603 return;
3604 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003605 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 }
3607
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003608 private boolean onLoadSoundEffects() {
3609 int status;
3610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003611 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003612 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003613 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3614 return false;
3615 }
3616
3617 if (mSoundPool != null) {
3618 return true;
3619 }
3620
3621 loadTouchSoundAssets();
3622
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003623 mSoundPool = new SoundPool.Builder()
3624 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3625 .setAudioAttributes(new AudioAttributes.Builder()
3626 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3627 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3628 .build())
3629 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003630 mSoundPoolCallBack = null;
3631 mSoundPoolListenerThread = new SoundPoolListenerThread();
3632 mSoundPoolListenerThread.start();
3633 int attempts = 3;
3634 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3635 try {
3636 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003637 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003638 } catch (InterruptedException e) {
3639 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3640 }
3641 }
3642
3643 if (mSoundPoolCallBack == null) {
3644 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3645 if (mSoundPoolLooper != null) {
3646 mSoundPoolLooper.quit();
3647 mSoundPoolLooper = null;
3648 }
3649 mSoundPoolListenerThread = null;
3650 mSoundPool.release();
3651 mSoundPool = null;
3652 return false;
3653 }
3654 /*
3655 * poolId table: The value -1 in this table indicates that corresponding
3656 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3657 * Once loaded, the value in poolId is the sample ID and the same
3658 * sample can be reused for another effect using the same file.
3659 */
3660 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3661 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3662 poolId[fileIdx] = -1;
3663 }
3664 /*
3665 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3666 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3667 * this indicates we have a valid sample loaded for this effect.
3668 */
3669
3670 int numSamples = 0;
3671 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3672 // Do not load sample if this effect uses the MediaPlayer
3673 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3674 continue;
3675 }
3676 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3677 String filePath = Environment.getRootDirectory()
3678 + SOUND_EFFECTS_PATH
3679 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3680 int sampleId = mSoundPool.load(filePath, 0);
3681 if (sampleId <= 0) {
3682 Log.w(TAG, "Soundpool could not load file: "+filePath);
3683 } else {
3684 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3685 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3686 numSamples++;
3687 }
3688 } else {
3689 SOUND_EFFECT_FILES_MAP[effect][1] =
3690 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3691 }
3692 }
3693 // wait for all samples to be loaded
3694 if (numSamples > 0) {
3695 mSoundPoolCallBack.setSamples(poolId);
3696
3697 attempts = 3;
3698 status = 1;
3699 while ((status == 1) && (attempts-- > 0)) {
3700 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003701 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003702 status = mSoundPoolCallBack.status();
3703 } catch (InterruptedException e) {
3704 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3705 }
3706 }
3707 } else {
3708 status = -1;
3709 }
3710
3711 if (mSoundPoolLooper != null) {
3712 mSoundPoolLooper.quit();
3713 mSoundPoolLooper = null;
3714 }
3715 mSoundPoolListenerThread = null;
3716 if (status != 0) {
3717 Log.w(TAG,
3718 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3719 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3720 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3721 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3722 }
3723 }
3724
3725 mSoundPool.release();
3726 mSoundPool = null;
3727 }
3728 }
3729 return (status == 0);
3730 }
3731
3732 /**
3733 * Unloads samples from the sound pool.
3734 * This method can be called to free some memory when
3735 * sound effects are disabled.
3736 */
3737 private void onUnloadSoundEffects() {
3738 synchronized (mSoundEffectsLock) {
3739 if (mSoundPool == null) {
3740 return;
3741 }
3742
3743 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3744 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3745 poolId[fileIdx] = 0;
3746 }
3747
3748 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3749 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3750 continue;
3751 }
3752 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3753 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3754 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3755 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3756 }
3757 }
3758 mSoundPool.release();
3759 mSoundPool = null;
3760 }
3761 }
3762
3763 private void onPlaySoundEffect(int effectType, int volume) {
3764 synchronized (mSoundEffectsLock) {
3765
3766 onLoadSoundEffects();
3767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 if (mSoundPool == null) {
3769 return;
3770 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003771 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003772 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003773 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003774 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003775 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003776 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778
3779 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003780 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3781 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003782 } else {
3783 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003784 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003785 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3786 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003787 mediaPlayer.setDataSource(filePath);
3788 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3789 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003790 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003791 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3792 public void onCompletion(MediaPlayer mp) {
3793 cleanupPlayer(mp);
3794 }
3795 });
3796 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3797 public boolean onError(MediaPlayer mp, int what, int extra) {
3798 cleanupPlayer(mp);
3799 return true;
3800 }
3801 });
3802 mediaPlayer.start();
3803 } catch (IOException ex) {
3804 Log.w(TAG, "MediaPlayer IOException: "+ex);
3805 } catch (IllegalArgumentException ex) {
3806 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3807 } catch (IllegalStateException ex) {
3808 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003809 }
3810 }
3811 }
3812 }
3813
3814 private void cleanupPlayer(MediaPlayer mp) {
3815 if (mp != null) {
3816 try {
3817 mp.stop();
3818 mp.release();
3819 } catch (IllegalStateException ex) {
3820 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3821 }
3822 }
3823 }
3824
Eric Laurentfa640152011-03-12 15:59:51 -08003825 private void setForceUse(int usage, int config) {
3826 AudioSystem.setForceUse(usage, config);
3827 }
3828
Eric Laurent05274f32012-11-29 12:48:18 -08003829 private void onPersistSafeVolumeState(int state) {
3830 Settings.Global.putInt(mContentResolver,
3831 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3832 state);
3833 }
3834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003835 @Override
3836 public void handleMessage(Message msg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837
Eric Laurentafbb0472011-12-15 09:04:23 -08003838 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003839
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003840 case MSG_SET_DEVICE_VOLUME:
3841 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3842 break;
3843
3844 case MSG_SET_ALL_VOLUMES:
3845 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 break;
3847
3848 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07003849 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 break;
3851
Mike Lockwood5c55a052011-12-15 17:21:44 -05003852 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07003853 if (mUseFixedVolume) {
3854 return;
3855 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003856 Settings.System.putFloatForUser(mContentResolver,
3857 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07003858 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003859 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05003860 break;
3861
Justin Koh57978ed2012-04-03 17:37:58 -07003862 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07003863 if (mUseFixedVolume) {
3864 return;
3865 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003866 Settings.System.putIntForUser(mContentResolver,
3867 Settings.System.VOLUME_MASTER_MUTE,
3868 msg.arg1,
3869 UserHandle.USER_CURRENT);
Justin Koh57978ed2012-04-03 17:37:58 -07003870 break;
3871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08003873 // note that the value persisted is the current ringer mode, not the
3874 // value of ringer mode as of the time the request was made to persist
3875 persistRingerMode(getRingerMode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 break;
3877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07003879 if (!mSystemReady ||
3880 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07003881 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08003882 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07003883 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07003884 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07003885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003886 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07003887
Eric Laurent3c652ca2010-06-21 20:46:26 -07003888 // indicate to audio HAL that we start the reconfiguration phase after a media
3889 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07003890 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07003891 // process restarts after a crash, not the first time it is started.
3892 AudioSystem.setParameters("restarting=true");
3893
Glenn Kastenfd116ad2013-07-12 17:10:39 -07003894 readAndSetLowRamDevice();
3895
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003896 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003897 synchronized (mConnectedDevices) {
3898 Set set = mConnectedDevices.entrySet();
3899 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003900 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003901 Map.Entry device = (Map.Entry)i.next();
3902 AudioSystem.setDeviceConnectionState(
3903 ((Integer)device.getKey()).intValue(),
3904 AudioSystem.DEVICE_STATE_AVAILABLE,
3905 (String)device.getValue());
3906 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003907 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003908 // Restore call state
3909 AudioSystem.setPhoneState(mMode);
3910
Eric Laurentd5603c12009-08-06 08:49:39 -07003911 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003912 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07003913 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07003914 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3915 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003916
Eric Laurenta553c252009-07-17 12:17:14 -07003917 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003918 int numStreamTypes = AudioSystem.getNumStreamTypes();
3919 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003920 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003921 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003922
3923 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003924 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003925
3926 // Restore ringer mode
3927 setRingerModeInt(getRingerMode(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07003928
Mike Lockwood90631542012-01-06 11:20:37 -05003929 // Restore master volume
3930 restoreMasterVolume();
3931
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003932 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07003933 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003934 setOrientationForAudioSystem();
3935 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07003936 if (mMonitorRotation) {
3937 setRotationForAudioSystem();
3938 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003939
Eric Laurent78472112012-05-21 08:57:21 -07003940 synchronized (mBluetoothA2dpEnabledLock) {
3941 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3942 mBluetoothA2dpEnabled ?
3943 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3944 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07003945
3946 synchronized (mSettingsLock) {
3947 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3948 mDockAudioMediaEnabled ?
3949 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3950 }
Eric Laurent212532b2014-07-21 15:43:18 -07003951 if (mHdmiManager != null) {
3952 synchronized (mHdmiManager) {
3953 if (mHdmiTvClient != null) {
3954 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
3955 }
3956 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09003957 }
Eric Laurent3c652ca2010-06-21 20:46:26 -07003958 // indicate the end of reconfiguration phase to audio HAL
3959 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960 break;
3961
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003962 case MSG_UNLOAD_SOUND_EFFECTS:
3963 onUnloadSoundEffects();
3964 break;
3965
Eric Laurent117b7bb2011-01-16 17:07:27 -08003966 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003967 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3968 // can take several dozens of milliseconds to complete
3969 boolean loaded = onLoadSoundEffects();
3970 if (msg.obj != null) {
3971 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3972 synchronized (reply) {
3973 reply.mStatus = loaded ? 0 : -1;
3974 reply.notify();
3975 }
3976 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08003977 break;
3978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003979 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003980 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003981 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003982
3983 case MSG_BTA2DP_DOCK_TIMEOUT:
3984 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003985 synchronized (mConnectedDevices) {
3986 makeA2dpDeviceUnavailableNow( (String) msg.obj );
3987 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003988 break;
Eric Laurentfa640152011-03-12 15:59:51 -08003989
3990 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07003991 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08003992 setForceUse(msg.arg1, msg.arg2);
3993 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07003994
Eric Laurentdc03c612011-04-01 10:59:41 -07003995 case MSG_BT_HEADSET_CNCT_FAILED:
3996 resetBluetoothSco();
3997 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003998
3999 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
4000 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004001 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004002 break;
4003
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004004 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4005 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4006 mAudioEventWakeLock.release();
4007 break;
4008
4009 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4010 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004011 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004012 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004013
4014 case MSG_REPORT_NEW_ROUTES: {
4015 int N = mRoutesObservers.beginBroadcast();
4016 if (N > 0) {
4017 AudioRoutesInfo routes;
4018 synchronized (mCurAudioRoutes) {
4019 routes = new AudioRoutesInfo(mCurAudioRoutes);
4020 }
4021 while (N > 0) {
4022 N--;
4023 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4024 try {
4025 obs.dispatchAudioRoutesChanged(routes);
4026 } catch (RemoteException e) {
4027 }
4028 }
4029 }
4030 mRoutesObservers.finishBroadcast();
4031 break;
4032 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004033
Eric Laurentc34dcc12012-09-10 13:51:52 -07004034 case MSG_CHECK_MUSIC_ACTIVE:
4035 onCheckMusicActive();
4036 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004037
4038 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4039 onSendBecomingNoisyIntent();
4040 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004041
4042 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4043 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4044 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4045 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004046 case MSG_PERSIST_SAFE_VOLUME_STATE:
4047 onPersistSafeVolumeState(msg.arg1);
4048 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004049
Eric Laurent2a57ca92013-03-07 17:29:27 -08004050 case MSG_BROADCAST_BT_CONNECTION_STATE:
4051 onBroadcastScoConnectionState(msg.arg1);
4052 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004053
4054 case MSG_SYSTEM_READY:
4055 onSystemReady();
4056 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004057
4058 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4059 final int musicActiveMs = msg.arg1;
4060 Settings.Secure.putIntForUser(mContentResolver,
4061 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4062 UserHandle.USER_CURRENT);
4063 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004064 }
4065 }
4066 }
4067
Jason Parekhb1096152009-03-24 17:48:25 -07004068 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004069
Jason Parekhb1096152009-03-24 17:48:25 -07004070 SettingsObserver() {
4071 super(new Handler());
4072 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4073 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004074 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4075 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004076 }
4077
4078 @Override
4079 public void onChange(boolean selfChange) {
4080 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004081 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4082 // However there appear to be some missing locks around mRingerModeMutedStreams
4083 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4084 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004085 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004086 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004087 /*
4088 * Ensure all stream types that should be affected by ringer mode
4089 * are in the proper state.
4090 */
Eric Laurenta553c252009-07-17 12:17:14 -07004091 setRingerModeInt(getRingerMode(), false);
4092 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004093 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004094 }
Jason Parekhb1096152009-03-24 17:48:25 -07004095 }
Jason Parekhb1096152009-03-24 17:48:25 -07004096 }
Eric Laurenta553c252009-07-17 12:17:14 -07004097
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004098 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004099 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004100 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4101 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004102 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4103 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4104 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004105 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004106 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4107 AudioSystem.DEVICE_STATE_AVAILABLE,
4108 address);
4109 // Reset A2DP suspend state each time a new sink is connected
4110 AudioSystem.setParameters("A2dpSuspended=false");
4111 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4112 address);
4113 }
4114
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004115 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004116 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004117 }
4118
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004119 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004120 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004121 synchronized (mA2dpAvrcpLock) {
4122 mAvrcpAbsVolSupported = false;
4123 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004124 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4125 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4126 address);
4127 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4128 }
4129
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004130 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004131 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004132 // prevent any activity on the A2DP audio output to avoid unwanted
4133 // reconnection of the sink.
4134 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004135 // the device will be made unavailable later, so consider it disconnected right away
4136 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4137 // send the delayed message to make the device unavailable later
4138 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4139 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4140
4141 }
4142
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004143 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004144 private void makeA2dpSrcAvailable(String address) {
4145 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4146 AudioSystem.DEVICE_STATE_AVAILABLE,
4147 address);
4148 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4149 address);
4150 }
4151
4152 // must be called synchronized on mConnectedDevices
4153 private void makeA2dpSrcUnavailable(String address) {
4154 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4155 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4156 address);
4157 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4158 }
4159
4160 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004161 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004162 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4163 }
4164
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004165 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004166 private boolean hasScheduledA2dpDockTimeout() {
4167 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4168 }
4169
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004170 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004171 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004172 if (DEBUG_VOL) {
4173 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4174 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004175 if (btDevice == null) {
4176 return;
4177 }
4178 String address = btDevice.getAddress();
4179 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4180 address = "";
4181 }
John Du5a0cf7a2013-07-19 11:30:34 -07004182
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004183 synchronized (mConnectedDevices) {
4184 boolean isConnected =
4185 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4186 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4187
4188 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4189 if (btDevice.isBluetoothDock()) {
4190 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4191 // introduction of a delay for transient disconnections of docks when
4192 // power is rapidly turned off/on, this message will be canceled if
4193 // we reconnect the dock under a preset delay
4194 makeA2dpDeviceUnavailableLater(address);
4195 // the next time isConnected is evaluated, it will be false for the dock
4196 }
4197 } else {
4198 makeA2dpDeviceUnavailableNow(address);
4199 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004200 synchronized (mCurAudioRoutes) {
4201 if (mCurAudioRoutes.mBluetoothName != null) {
4202 mCurAudioRoutes.mBluetoothName = null;
4203 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4204 SENDMSG_NOOP, 0, 0, null, 0);
4205 }
4206 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004207 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4208 if (btDevice.isBluetoothDock()) {
4209 // this could be a reconnection after a transient disconnection
4210 cancelA2dpDeviceTimeout();
4211 mDockAddress = address;
4212 } else {
4213 // this could be a connection of another A2DP device before the timeout of
4214 // a dock: cancel the dock timeout, and make the dock unavailable now
4215 if(hasScheduledA2dpDockTimeout()) {
4216 cancelA2dpDeviceTimeout();
4217 makeA2dpDeviceUnavailableNow(mDockAddress);
4218 }
4219 }
4220 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004221 synchronized (mCurAudioRoutes) {
4222 String name = btDevice.getAliasName();
4223 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4224 mCurAudioRoutes.mBluetoothName = name;
4225 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4226 SENDMSG_NOOP, 0, 0, null, 0);
4227 }
4228 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004229 }
4230 }
4231 }
4232
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004233 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4234 {
4235 if (DEBUG_VOL) {
4236 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4237 }
4238 if (btDevice == null) {
4239 return;
4240 }
4241 String address = btDevice.getAddress();
4242 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4243 address = "";
4244 }
4245
4246 synchronized (mConnectedDevices) {
4247 boolean isConnected =
4248 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4249 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4250
4251 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4252 makeA2dpSrcUnavailable(address);
4253 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4254 makeA2dpSrcAvailable(address);
4255 }
4256 }
4257 }
4258
John Du5a0cf7a2013-07-19 11:30:34 -07004259 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4260 // address is not used for now, but may be used when multiple a2dp devices are supported
4261 synchronized (mA2dpAvrcpLock) {
4262 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004263 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004264 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4265 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4266 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4267 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4268 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004269 }
4270 }
4271
Eric Laurent59f48272012-04-05 19:42:21 -07004272 private boolean handleDeviceConnection(boolean connected, int device, String params) {
4273 synchronized (mConnectedDevices) {
4274 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Mike Lockwood98418182012-05-10 17:13:20 -07004275 (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
Eric Laurent59f48272012-04-05 19:42:21 -07004276
4277 if (isConnected && !connected) {
4278 AudioSystem.setDeviceConnectionState(device,
4279 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Mike Lockwood98418182012-05-10 17:13:20 -07004280 mConnectedDevices.get(device));
Eric Laurent59f48272012-04-05 19:42:21 -07004281 mConnectedDevices.remove(device);
4282 return true;
4283 } else if (!isConnected && connected) {
4284 AudioSystem.setDeviceConnectionState(device,
4285 AudioSystem.DEVICE_STATE_AVAILABLE,
4286 params);
4287 mConnectedDevices.put(new Integer(device), params);
4288 return true;
4289 }
4290 }
4291 return false;
4292 }
4293
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004294 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4295 // sent if none of these devices is connected.
4296 int mBecomingNoisyIntentDevices =
4297 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004298 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004299 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004300 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004301
4302 // must be called before removing the device from mConnectedDevices
4303 private int checkSendBecomingNoisyIntent(int device, int state) {
4304 int delay = 0;
4305 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4306 int devices = 0;
4307 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004308 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4309 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004310 devices |= dev;
4311 }
4312 }
4313 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004314 sendMsg(mAudioHandler,
4315 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4316 SENDMSG_REPLACE,
4317 0,
4318 0,
4319 null,
4320 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004321 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004322 }
4323 }
4324
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004325 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4326 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004327 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4328 delay = 1000;
4329 }
4330 return delay;
4331 }
4332
4333 private void sendDeviceConnectionIntent(int device, int state, String name)
4334 {
4335 Intent intent = new Intent();
4336
4337 intent.putExtra("state", state);
4338 intent.putExtra("name", name);
4339 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4340
Dianne Hackborn632ca412012-06-14 19:34:10 -07004341 int connType = 0;
4342
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004343 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004344 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004345 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4346 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004347 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4348 device == AudioSystem.DEVICE_OUT_LINE) {
4349 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004350 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004351 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4352 intent.putExtra("microphone", 0);
4353 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004354 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004355 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4356 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004357 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004358 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
Eric Laurent948d3272014-05-16 15:18:45 -07004359 } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004360 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004361 configureHdmiPlugIntent(intent, state);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004362 }
4363
Dianne Hackborn632ca412012-06-14 19:34:10 -07004364 synchronized (mCurAudioRoutes) {
4365 if (connType != 0) {
4366 int newConn = mCurAudioRoutes.mMainType;
4367 if (state != 0) {
4368 newConn |= connType;
4369 } else {
4370 newConn &= ~connType;
4371 }
4372 if (newConn != mCurAudioRoutes.mMainType) {
4373 mCurAudioRoutes.mMainType = newConn;
4374 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4375 SENDMSG_NOOP, 0, 0, null, 0);
4376 }
4377 }
4378 }
4379
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004380 final long ident = Binder.clearCallingIdentity();
4381 try {
4382 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4383 } finally {
4384 Binder.restoreCallingIdentity(ident);
4385 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004386 }
4387
4388 private void onSetWiredDeviceConnectionState(int device, int state, String name)
4389 {
4390 synchronized (mConnectedDevices) {
4391 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004392 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4393 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004394 setBluetoothA2dpOnInt(true);
4395 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004396 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4397 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4398 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Mike Lockwooddb454842012-09-18 11:16:57 -07004399 handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
Eric Laurentf1a457d2012-09-20 16:27:23 -07004400 if (state != 0) {
4401 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004402 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4403 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004404 setBluetoothA2dpOnInt(false);
4405 }
4406 if ((device & mSafeMediaVolumeDevices) != 0) {
4407 sendMsg(mAudioHandler,
4408 MSG_CHECK_MUSIC_ACTIVE,
4409 SENDMSG_REPLACE,
4410 0,
4411 0,
4412 null,
4413 MUSIC_ACTIVE_POLL_PERIOD_MS);
4414 }
Eric Laurent212532b2014-07-21 15:43:18 -07004415 // Television devices without CEC service apply software volume on HDMI output
4416 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4417 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4418 checkAllFixedVolumeDevices();
4419 if (mHdmiManager != null) {
4420 synchronized (mHdmiManager) {
4421 if (mHdmiPlaybackClient != null) {
4422 mHdmiCecSink = false;
4423 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4424 }
4425 }
4426 }
4427 }
4428 } else {
4429 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4430 if (mHdmiManager != null) {
4431 synchronized (mHdmiManager) {
4432 mHdmiCecSink = false;
4433 }
4434 }
4435 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004436 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004437 if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
Mike Lockwooddb454842012-09-18 11:16:57 -07004438 sendDeviceConnectionIntent(device, state, name);
4439 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004440 }
4441 }
4442
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004443 private void configureHdmiPlugIntent(Intent intent, int state) {
4444 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4445 if (state == 1) {
4446 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4447 int[] portGeneration = new int[1];
4448 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4449 if (status == AudioManager.SUCCESS) {
4450 for (AudioPort port : ports) {
4451 if (port instanceof AudioDevicePort) {
4452 final AudioDevicePort devicePort = (AudioDevicePort) port;
4453 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI) {
4454 // format the list of supported encodings
4455 int[] formats = devicePort.formats();
4456 if (formats.length > 0) {
4457 ArrayList<Integer> encodingList = new ArrayList(1);
4458 for (int format : formats) {
4459 // a format in the list can be 0, skip it
4460 if (format != AudioFormat.ENCODING_INVALID) {
4461 encodingList.add(format);
4462 }
4463 }
4464 int[] encodingArray = new int[encodingList.size()];
4465 for (int i = 0 ; i < encodingArray.length ; i++) {
4466 encodingArray[i] = encodingList.get(i);
4467 }
4468 intent.putExtra("encodings", encodingArray);
4469 }
4470 // find the maximum supported number of channels
4471 int maxChannels = 0;
4472 for (int mask : devicePort.channelMasks()) {
4473 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4474 if (channelCount > maxChannels) {
4475 maxChannels = channelCount;
4476 }
4477 }
4478 intent.putExtra("maxChannelCount", maxChannels);
4479 }
4480 }
4481 }
4482 }
4483 }
4484 }
4485
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004486 /* cache of the address of the last dock the device was connected to */
4487 private String mDockAddress;
4488
Eric Laurenta553c252009-07-17 12:17:14 -07004489 /**
4490 * Receiver for misc intent broadcasts the Phone app cares about.
4491 */
4492 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4493 @Override
4494 public void onReceive(Context context, Intent intent) {
4495 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004496 int outDevice;
4497 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004498 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004499
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004500 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4501 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4502 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4503 int config;
4504 switch (dockState) {
4505 case Intent.EXTRA_DOCK_STATE_DESK:
4506 config = AudioSystem.FORCE_BT_DESK_DOCK;
4507 break;
4508 case Intent.EXTRA_DOCK_STATE_CAR:
4509 config = AudioSystem.FORCE_BT_CAR_DOCK;
4510 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004511 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004512 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004513 break;
4514 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4515 config = AudioSystem.FORCE_DIGITAL_DOCK;
4516 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004517 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4518 default:
4519 config = AudioSystem.FORCE_NONE;
4520 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004521 // Low end docks have a menu to enable or disable audio
4522 // (see mDockAudioMediaEnabled)
4523 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4524 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4525 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4526 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4527 }
4528 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004529 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004530 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004531 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004532 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4533 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004534 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004535
4536 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4537 if (btDevice == null) {
4538 return;
4539 }
4540
4541 address = btDevice.getAddress();
4542 BluetoothClass btClass = btDevice.getBluetoothClass();
4543 if (btClass != null) {
4544 switch (btClass.getDeviceClass()) {
4545 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4546 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004547 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004548 break;
4549 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004550 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004551 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004552 }
4553 }
4554
Eric Laurentdca56b92011-09-02 14:20:56 -07004555 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4556 address = "";
4557 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004558
Eric Laurent59f48272012-04-05 19:42:21 -07004559 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004560 boolean success = handleDeviceConnection(connected, outDevice, address) &&
4561 handleDeviceConnection(connected, inDevice, address);
4562 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004563 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004564 if (connected) {
4565 mBluetoothHeadsetDevice = btDevice;
4566 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004567 mBluetoothHeadsetDevice = null;
4568 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004569 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004570 }
Eric Laurenta553c252009-07-17 12:17:14 -07004571 }
Paul McLeandf361462014-04-10 16:02:55 -07004572 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4573 state = intent.getIntExtra("state", 0);
4574
4575 int alsaCard = intent.getIntExtra("card", -1);
4576 int alsaDevice = intent.getIntExtra("device", -1);
4577
4578 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4579 : "card=" + alsaCard + ";device=" + alsaDevice);
4580
4581 // Playback Device
Eric Laurentae4506e2014-05-29 16:04:32 -07004582 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4583 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004584 } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
Glenn Kasten5f516352014-07-22 09:11:48 -07004585 // FIXME Does not yet handle the case where the setting is changed
4586 // after device connection. Ideally we should handle the settings change
4587 // in SettingsObserver. Here we should log that a USB device is connected
4588 // and disconnected with its address (card , device) and force the
4589 // connection or disconnection when the setting changes.
Glenn Kasten34cc4db2014-08-13 10:56:38 -07004590 int isDisabled = Settings.Secure.getInt(mContentResolver,
4591 Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
Glenn Kasten5f516352014-07-22 09:11:48 -07004592 if (isDisabled != 0) {
4593 return;
4594 }
4595
Eric Laurent59f48272012-04-05 19:42:21 -07004596 state = intent.getIntExtra("state", 0);
Paul McLeanc837a452014-04-09 09:04:43 -07004597
Eric Laurent59f48272012-04-05 19:42:21 -07004598 int alsaCard = intent.getIntExtra("card", -1);
4599 int alsaDevice = intent.getIntExtra("device", -1);
Paul McLeanc837a452014-04-09 09:04:43 -07004600 boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4601 boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4602 boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4603
Mike Lockwood98418182012-05-10 17:13:20 -07004604 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4605 : "card=" + alsaCard + ";device=" + alsaDevice);
Paul McLeanc837a452014-04-09 09:04:43 -07004606
Paul McLeanc837a452014-04-09 09:04:43 -07004607 // Playback Device
Paul McLeandf361462014-04-10 16:02:55 -07004608 if (hasPlayback) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004609 outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4610 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004611 }
Paul McLeanc837a452014-04-09 09:04:43 -07004612
4613 // Capture Device
Paul McLeandf361462014-04-10 16:02:55 -07004614 if (hasCapture) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004615 inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4616 setWiredDeviceConnectionState(inDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004617 }
4618 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004619 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004620 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004621 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004622 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004623 // broadcast intent if the connection was initated by AudioService
4624 if (!mScoClients.isEmpty() &&
4625 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4626 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4627 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004628 broadcast = true;
4629 }
4630 switch (btState) {
4631 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004632 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004633 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4634 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4635 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004636 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004637 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004638 break;
4639 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004640 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004641 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004642 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004643 break;
4644 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004645 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4646 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4647 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004648 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004649 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004650 default:
4651 // do not broadcast CONNECTING or invalid state
4652 broadcast = false;
4653 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004654 }
4655 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004656 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004657 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004658 //FIXME: this is to maintain compatibility with deprecated intent
4659 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004660 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004661 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004662 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004663 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004664 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4665 AudioSystem.setParameters("screen_state=on");
4666 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4667 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004668 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004669 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004670 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004671 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004672 sendMsg(mAudioHandler,
4673 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4674 SENDMSG_REPLACE,
4675 0,
4676 0,
4677 null,
4678 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004679 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004680 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004681
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004682 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004683 readAudioSettings(true /*userSwitch*/);
4684 // preserve STREAM_MUSIC volume from one user to the next.
4685 sendMsg(mAudioHandler,
4686 MSG_SET_ALL_VOLUMES,
4687 SENDMSG_QUEUE,
4688 0,
4689 0,
4690 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004691 }
4692 }
Paul McLeanc837a452014-04-09 09:04:43 -07004693 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004694
4695 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004696 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004697 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004698 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4699 ComponentName listenerComp) {
4700 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4701 }
4702
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004703 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004704 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004705 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004706
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004707 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004708 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004709 }
4710
4711 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004712 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004713 }
4714
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004715 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4716 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004717 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4718 }
4719
John Spurlock3346a802014-05-20 16:25:37 -04004720 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004721 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04004722 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004723 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004724 }
4725
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004726 //==========================================================================================
4727 // Audio Focus
4728 //==========================================================================================
4729 public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4730 IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4731 return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4732 clientId, callingPackageName);
4733 }
4734
4735 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4736 return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4737 }
4738
4739 public void unregisterAudioFocusClient(String clientId) {
4740 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004741 }
4742
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004743 public int getCurrentAudioFocus() {
4744 return mMediaFocusControl.getCurrentAudioFocus();
4745 }
4746
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004747 //==========================================================================================
4748 // Device orientation
4749 //==========================================================================================
4750 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004751 * Handles device configuration changes that may map to a change in the orientation
4752 * or orientation.
4753 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4754 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004755 */
4756 private void handleConfigurationChanged(Context context) {
4757 try {
4758 // reading new orientation "safely" (i.e. under try catch) in case anything
4759 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004760 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004761 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004762 if (mMonitorOrientation) {
4763 int newOrientation = config.orientation;
4764 if (newOrientation != mDeviceOrientation) {
4765 mDeviceOrientation = newOrientation;
4766 setOrientationForAudioSystem();
4767 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004768 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004769 if (mMonitorRotation) {
4770 int newRotation = ((WindowManager) context.getSystemService(
4771 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4772 if (newRotation != mDeviceRotation) {
4773 mDeviceRotation = newRotation;
4774 setRotationForAudioSystem();
4775 }
4776 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004777 sendMsg(mAudioHandler,
4778 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4779 SENDMSG_REPLACE,
4780 0,
4781 0,
4782 null,
4783 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004784
4785 boolean cameraSoundForced = mContext.getResources().getBoolean(
4786 com.android.internal.R.bool.config_camera_sound_forced);
4787 synchronized (mSettingsLock) {
4788 synchronized (mCameraSoundForced) {
4789 if (cameraSoundForced != mCameraSoundForced) {
4790 mCameraSoundForced = cameraSoundForced;
4791
Eric Laurent212532b2014-07-21 15:43:18 -07004792 if (!isPlatformTelevision()) {
4793 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4794 if (cameraSoundForced) {
4795 s.setAllIndexesToMax();
4796 mRingerModeAffectedStreams &=
4797 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4798 } else {
4799 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4800 mRingerModeAffectedStreams |=
4801 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4802 }
4803 // take new state into account for streams muted by ringer mode
4804 setRingerModeInt(getRingerMode(), false);
Eric Laurentdd45d012012-10-08 09:04:34 -07004805 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004806
4807 sendMsg(mAudioHandler,
4808 MSG_SET_FORCE_USE,
4809 SENDMSG_QUEUE,
4810 AudioSystem.FOR_SYSTEM,
4811 cameraSoundForced ?
4812 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4813 null,
4814 0);
4815
4816 sendMsg(mAudioHandler,
4817 MSG_SET_ALL_VOLUMES,
4818 SENDMSG_QUEUE,
4819 0,
4820 0,
4821 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4822 }
4823 }
4824 }
John Spurlock3346a802014-05-20 16:25:37 -04004825 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004826 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004827 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004828 }
4829 }
4830
4831 private void setOrientationForAudioSystem() {
4832 switch (mDeviceOrientation) {
4833 case Configuration.ORIENTATION_LANDSCAPE:
4834 //Log.i(TAG, "orientation is landscape");
4835 AudioSystem.setParameters("orientation=landscape");
4836 break;
4837 case Configuration.ORIENTATION_PORTRAIT:
4838 //Log.i(TAG, "orientation is portrait");
4839 AudioSystem.setParameters("orientation=portrait");
4840 break;
4841 case Configuration.ORIENTATION_SQUARE:
4842 //Log.i(TAG, "orientation is square");
4843 AudioSystem.setParameters("orientation=square");
4844 break;
4845 case Configuration.ORIENTATION_UNDEFINED:
4846 //Log.i(TAG, "orientation is undefined");
4847 AudioSystem.setParameters("orientation=undefined");
4848 break;
4849 default:
4850 Log.e(TAG, "Unknown orientation");
4851 }
4852 }
4853
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004854 private void setRotationForAudioSystem() {
4855 switch (mDeviceRotation) {
4856 case Surface.ROTATION_0:
4857 AudioSystem.setParameters("rotation=0");
4858 break;
4859 case Surface.ROTATION_90:
4860 AudioSystem.setParameters("rotation=90");
4861 break;
4862 case Surface.ROTATION_180:
4863 AudioSystem.setParameters("rotation=180");
4864 break;
4865 case Surface.ROTATION_270:
4866 AudioSystem.setParameters("rotation=270");
4867 break;
4868 default:
4869 Log.e(TAG, "Unknown device rotation");
4870 }
4871 }
4872
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004873
Eric Laurent78472112012-05-21 08:57:21 -07004874 // Handles request to override default use of A2DP for media.
4875 public void setBluetoothA2dpOnInt(boolean on) {
4876 synchronized (mBluetoothA2dpEnabledLock) {
4877 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07004878 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4879 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4880 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07004881 }
4882 }
4883
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004884 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07004885 public void setRingtonePlayer(IRingtonePlayer player) {
4886 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4887 mRingtonePlayer = player;
4888 }
4889
4890 @Override
4891 public IRingtonePlayer getRingtonePlayer() {
4892 return mRingtonePlayer;
4893 }
4894
4895 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07004896 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4897 synchronized (mCurAudioRoutes) {
4898 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4899 mRoutesObservers.register(observer);
4900 return routes;
4901 }
4902 }
4903
Eric Laurentc34dcc12012-09-10 13:51:52 -07004904
4905 //==========================================================================================
4906 // Safe media volume management.
4907 // MUSIC stream volume level is limited when headphones are connected according to safety
4908 // regulation. When the user attempts to raise the volume above the limit, a warning is
4909 // displayed and the user has to acknowlegde before the volume is actually changed.
4910 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4911 // property. Platforms with a different limit must set this property accordingly in their
4912 // overlay.
4913 //==========================================================================================
4914
Eric Laurentd640bd32012-09-28 18:01:48 -07004915 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4916 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4917 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4918 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4919 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4920 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04004921 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4922 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4923 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
4924 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07004925 private Integer mSafeMediaVolumeState;
4926
4927 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004928 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07004929 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004930 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4931 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4932 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4933 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4934 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4935 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4936 private int mMusicActiveMs;
4937 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4938 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07004939 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07004940
4941 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004942 synchronized (mSafeMediaVolumeState) {
4943 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4944 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4945 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4946 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4947 enforceSafeMediaVolume();
4948 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4949 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004950 mMusicActiveMs = 1; // nonzero = confirmed
4951 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07004952 sendMsg(mAudioHandler,
4953 MSG_CHECK_MUSIC_ACTIVE,
4954 SENDMSG_REPLACE,
4955 0,
4956 0,
4957 null,
4958 MUSIC_ACTIVE_POLL_PERIOD_MS);
4959 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004960 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004961 }
4962 }
4963
4964 private void enforceSafeMediaVolume() {
4965 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07004966 int devices = mSafeMediaVolumeDevices;
4967 int i = 0;
4968
4969 while (devices != 0) {
4970 int device = 1 << i++;
4971 if ((device & devices) == 0) {
4972 continue;
4973 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004974 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004975 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004976 streamState.setIndex(mSafeMediaVolumeIndex, device);
4977 sendMsg(mAudioHandler,
4978 MSG_SET_DEVICE_VOLUME,
4979 SENDMSG_QUEUE,
4980 device,
4981 0,
4982 streamState,
4983 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004984 }
4985 devices &= ~device;
4986 }
4987 }
4988
4989 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004990 synchronized (mSafeMediaVolumeState) {
4991 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07004992 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4993 ((device & mSafeMediaVolumeDevices) != 0) &&
4994 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004995 return false;
4996 }
4997 return true;
4998 }
4999 }
5000
John Spurlock3346a802014-05-20 16:25:37 -04005001 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005002 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04005003 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005004 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005005 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005006 if (mPendingVolumeCommand != null) {
5007 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5008 mPendingVolumeCommand.mIndex,
5009 mPendingVolumeCommand.mFlags,
5010 mPendingVolumeCommand.mDevice);
5011 mPendingVolumeCommand = null;
5012 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005013 }
5014 }
5015
Jungshik Jang41d97462014-06-30 22:26:29 +09005016 //==========================================================================================
5017 // Hdmi Cec system audio mode.
5018 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
5019 // to HdmiControlService so that audio recevier can handle volume change.
5020 //==========================================================================================
5021
Eric Laurent212532b2014-07-21 15:43:18 -07005022 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5023 public void onComplete(int status) {
5024 if (mHdmiManager != null) {
5025 synchronized (mHdmiManager) {
5026 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5027 // Television devices without CEC service apply software volume on HDMI output
5028 if (isPlatformTelevision() && !mHdmiCecSink) {
5029 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5030 }
5031 checkAllFixedVolumeDevices();
5032 }
5033 }
5034 }
5035 };
5036
Jungshik Jang41d97462014-06-30 22:26:29 +09005037 // If HDMI-CEC system audio is supported
5038 private boolean mHdmiSystemAudioSupported = false;
5039 // Set only when device is tv.
5040 private HdmiTvClient mHdmiTvClient;
Eric Laurent212532b2014-07-21 15:43:18 -07005041 // true if the device has system feature PackageManager.FEATURE_TELEVISION.
5042 // cached HdmiControlManager interface
5043 private HdmiControlManager mHdmiManager;
5044 // Set only when device is a set-top box.
5045 private HdmiPlaybackClient mHdmiPlaybackClient;
5046 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5047 private boolean mHdmiCecSink;
5048
5049 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005050
5051 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005052 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005053 int device = AudioSystem.DEVICE_NONE;
5054 if (mHdmiManager != null) {
5055 synchronized (mHdmiManager) {
5056 if (mHdmiTvClient == null) {
5057 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5058 return device;
5059 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005060
Eric Laurent212532b2014-07-21 15:43:18 -07005061 synchronized (mHdmiTvClient) {
5062 if (mHdmiSystemAudioSupported != on) {
5063 mHdmiSystemAudioSupported = on;
5064 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5065 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5066 AudioSystem.FORCE_NONE);
5067 }
5068 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5069 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005070 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005071 }
Eric Laurent212532b2014-07-21 15:43:18 -07005072 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005073 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005074
Eric Laurentdd45d012012-10-08 09:04:34 -07005075 //==========================================================================================
5076 // Camera shutter sound policy.
5077 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5078 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5079 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5080 //==========================================================================================
5081
5082 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5083 private Boolean mCameraSoundForced;
5084
5085 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5086 public boolean isCameraSoundForced() {
5087 synchronized (mCameraSoundForced) {
5088 return mCameraSoundForced;
5089 }
5090 }
5091
5092 private static final String[] RINGER_MODE_NAMES = new String[] {
5093 "SILENT",
5094 "VIBRATE",
5095 "NORMAL"
5096 };
5097
5098 private void dumpRingerMode(PrintWriter pw) {
5099 pw.println("\nRinger mode: ");
5100 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
5101 pw.print("- ringer mode affected streams = 0x");
5102 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5103 pw.print("- ringer mode muted streams = 0x");
5104 pw.println(Integer.toHexString(mRingerModeMutedStreams));
5105 }
5106
Dianne Hackborn632ca412012-06-14 19:34:10 -07005107 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005108 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005109 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5110
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005111 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005112 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005113 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005114 pw.println("\nAudio routes:");
5115 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5116 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005117
5118 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005119 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005120 pw.print(" mSafeMediaVolumeState=");
5121 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5122 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5123 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5124 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005125 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock35134602014-07-24 18:10:48 -04005126 }
5127
5128 private static String safeMediaVolumeStateToString(Integer state) {
5129 switch(state) {
5130 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5131 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5132 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5133 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5134 }
5135 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005136 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005137
5138 // Inform AudioFlinger of our device's low RAM attribute
5139 private static void readAndSetLowRamDevice()
5140 {
5141 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5142 if (status != 0) {
5143 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5144 }
5145 }
John Spurlock3346a802014-05-20 16:25:37 -04005146
5147 private void enforceSelfOrSystemUI(String action) {
5148 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5149 "Only SystemUI can " + action);
5150 }
5151
5152 @Override
5153 public void setVolumeController(final IVolumeController controller) {
5154 enforceSelfOrSystemUI("set the volume controller");
5155
5156 // return early if things are not actually changing
5157 if (mVolumeController.isSameBinder(controller)) {
5158 return;
5159 }
5160
5161 // dismiss the old volume controller
5162 mVolumeController.postDismiss();
5163 if (controller != null) {
5164 // we are about to register a new controller, listen for its death
5165 try {
5166 controller.asBinder().linkToDeath(new DeathRecipient() {
5167 @Override
5168 public void binderDied() {
5169 if (mVolumeController.isSameBinder(controller)) {
5170 Log.w(TAG, "Current remote volume controller died, unregistering");
5171 setVolumeController(null);
5172 }
5173 }
5174 }, 0);
5175 } catch (RemoteException e) {
5176 // noop
5177 }
5178 }
5179 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005180 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5181 }
5182
5183 @Override
5184 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5185 enforceSelfOrSystemUI("notify about volume controller visibility");
5186
5187 // return early if the controller is not current
5188 if (!mVolumeController.isSameBinder(controller)) {
5189 return;
5190 }
5191
5192 mVolumeController.setVisible(visible);
5193 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005194 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005195
5196 public static class VolumeController {
5197 private static final String TAG = "VolumeController";
5198
5199 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005200 private boolean mVisible;
5201 private long mNextLongPress;
5202 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005203
5204 public void setController(IVolumeController controller) {
5205 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005206 mVisible = false;
5207 }
5208
5209 public void loadSettings(ContentResolver cr) {
5210 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5211 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5212 }
5213
5214 public boolean suppressAdjustment(int resolvedStream, int flags) {
5215 boolean suppress = false;
5216 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5217 final long now = SystemClock.uptimeMillis();
5218 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5219 // ui will become visible
5220 if (mNextLongPress < now) {
5221 mNextLongPress = now + mLongPressTimeout;
5222 }
5223 suppress = true;
5224 } else if (mNextLongPress > 0) { // in a long-press
5225 if (now > mNextLongPress) {
5226 // long press triggered, no more suppression
5227 mNextLongPress = 0;
5228 } else {
5229 // keep suppressing until the long press triggers
5230 suppress = true;
5231 }
5232 }
5233 }
5234 return suppress;
5235 }
5236
5237 public void setVisible(boolean visible) {
5238 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005239 }
5240
5241 public boolean isSameBinder(IVolumeController controller) {
5242 return Objects.equals(asBinder(), binder(controller));
5243 }
5244
5245 public IBinder asBinder() {
5246 return binder(mController);
5247 }
5248
5249 private static IBinder binder(IVolumeController controller) {
5250 return controller == null ? null : controller.asBinder();
5251 }
5252
5253 @Override
5254 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005255 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005256 }
5257
5258 public void postDisplaySafeVolumeWarning(int flags) {
5259 if (mController == null)
5260 return;
5261 try {
5262 mController.displaySafeVolumeWarning(flags);
5263 } catch (RemoteException e) {
5264 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5265 }
5266 }
5267
5268 public void postVolumeChanged(int streamType, int flags) {
5269 if (mController == null)
5270 return;
5271 try {
5272 mController.volumeChanged(streamType, flags);
5273 } catch (RemoteException e) {
5274 Log.w(TAG, "Error calling volumeChanged", e);
5275 }
5276 }
5277
5278 public void postMasterVolumeChanged(int flags) {
5279 if (mController == null)
5280 return;
5281 try {
5282 mController.masterVolumeChanged(flags);
5283 } catch (RemoteException e) {
5284 Log.w(TAG, "Error calling masterVolumeChanged", e);
5285 }
5286 }
5287
5288 public void postMasterMuteChanged(int flags) {
5289 if (mController == null)
5290 return;
5291 try {
5292 mController.masterMuteChanged(flags);
5293 } catch (RemoteException e) {
5294 Log.w(TAG, "Error calling masterMuteChanged", e);
5295 }
5296 }
5297
5298 public void setLayoutDirection(int layoutDirection) {
5299 if (mController == null)
5300 return;
5301 try {
5302 mController.setLayoutDirection(layoutDirection);
5303 } catch (RemoteException e) {
5304 Log.w(TAG, "Error calling setLayoutDirection", e);
5305 }
5306 }
5307
5308 public void postDismiss() {
5309 if (mController == null)
5310 return;
5311 try {
5312 mController.dismiss();
5313 } catch (RemoteException e) {
5314 Log.w(TAG, "Error calling dismiss", e);
5315 }
5316 }
5317 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005318
RoboErik0dac35a2014-08-12 15:48:49 -07005319 /**
5320 * Interface for system components to get some extra functionality through
5321 * LocalServices.
5322 */
5323 final class AudioServiceInternal extends AudioManagerInternal {
5324 @Override
5325 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5326 String callingPackage, int uid) {
5327 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5328 }
5329
5330 @Override
5331 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5332 String callingPackage, int uid) {
5333 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5334 }
5335 }
5336
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005337 //==========================================================================================
5338 // Audio policy management
5339 //==========================================================================================
5340 public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
5341 //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
5342 boolean hasPermissionForPolicy =
5343 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
5344 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5345 if (!hasPermissionForPolicy) {
5346 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5347 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5348 return false;
5349 }
5350 synchronized (mAudioPolicies) {
5351 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
5352 try {
5353 cb.linkToDeath(app, 0/*flags*/);
5354 mAudioPolicies.put(cb, app);
5355 } catch (RemoteException e) {
5356 // audio policy owner has already died!
5357 Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
5358 " binder death", e);
5359 return false;
5360 }
5361 }
5362 // TODO implement registration with native audio policy (including permission check)
5363 return true;
5364 }
5365 public void unregisterAudioPolicyAsync(IBinder cb) {
5366 synchronized (mAudioPolicies) {
5367 AudioPolicyProxy app = mAudioPolicies.remove(cb);
5368 if (app == null) {
5369 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5370 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5371 } else {
5372 cb.unlinkToDeath(app, 0/*flags*/);
5373 }
5374 }
5375 // TODO implement registration with native audio policy
5376 }
5377
5378 public class AudioPolicyProxy implements IBinder.DeathRecipient {
5379 private static final String TAG = "AudioPolicyProxy";
5380 AudioPolicyConfig mConfig;
5381 IBinder mToken;
5382 AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
5383 mConfig = config;
5384 mToken = token;
5385 }
5386
5387 public void binderDied() {
5388 synchronized (mAudioPolicies) {
5389 Log.v(TAG, "audio policy " + mToken + " died");
5390 mAudioPolicies.remove(mToken);
5391 }
5392 }
5393 };
5394
5395 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5396 new HashMap<IBinder, AudioPolicyProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005397}