blob: dc564ba69e0dbf4edcc27b972b8e6c6b728f4186 [file] [log] [blame]
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08001/*
2 * Copyright (C) 2016 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 com.android.server.audio;
18
19import android.annotation.NonNull;
Eric Laurente5a351c2017-09-27 20:11:51 -070020import android.content.Context;
21import android.content.pm.PackageManager;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080022import android.media.AudioAttributes;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080023import android.media.AudioManager;
24import android.media.AudioPlaybackConfiguration;
25import android.media.AudioSystem;
26import android.media.IPlaybackConfigDispatcher;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080027import android.media.PlayerBase;
Jean-Michel Trividce82ab2017-02-07 16:02:33 -080028import android.media.VolumeShaper;
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -080029import android.os.Binder;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080030import android.os.IBinder;
31import android.os.RemoteException;
32import android.util.Log;
33
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -070034import com.android.internal.util.ArrayUtils;
35
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080036import java.io.PrintWriter;
37import java.text.DateFormat;
38import java.util.ArrayList;
Jean-Michel Trivi56266192017-07-18 14:53:40 -070039import java.util.Collections;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080040import java.util.Date;
41import java.util.HashMap;
42import java.util.Iterator;
43import java.util.List;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080044import java.util.Set;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080045
46/**
47 * Class to receive and dispatch updates from AudioSystem about recording configurations.
48 */
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -080049public final class PlaybackActivityMonitor
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -080050 implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080051
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070052 public static final String TAG = "AudioService.PlaybackActivityMonitor";
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -080053
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070054 private static final boolean DEBUG = false;
55 private static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080056
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070057 private static final VolumeShaper.Configuration DUCK_VSHAPE =
Andy Hung7da0e982017-02-22 12:34:21 -080058 new VolumeShaper.Configuration.Builder()
59 .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
60 .setCurve(new float[] { 0.f, 1.f } /* times */,
61 new float[] { 1.f, 0.2f } /* volumes */)
62 .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
Jean-Michel Trivi4c86efa12017-04-20 18:13:34 -070063 .setDuration(MediaFocusControl.getFocusRampTimeMs(
Andy Hung7da0e982017-02-22 12:34:21 -080064 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
65 new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
66 .build()))
67 .build();
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070068 private static final VolumeShaper.Configuration DUCK_ID =
Andy Hung7da0e982017-02-22 12:34:21 -080069 new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -070070 private static final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
Andy Hung7da0e982017-02-22 12:34:21 -080071 new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
72 .createIfNeeded()
73 .build();
Andy Hung7da0e982017-02-22 12:34:21 -080074
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -070075 // TODO support VolumeShaper on those players
76 private static final int[] UNDUCKABLE_PLAYER_TYPES = {
77 AudioPlaybackConfiguration.PLAYER_TYPE_AAUDIO,
78 AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL,
79 };
80
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -070081 // like a PLAY_CREATE_IF_NEEDED operation but with a skip to the end of the ramp
82 private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
83 new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
84
Andy Hung7da0e982017-02-22 12:34:21 -080085 private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080086 // a public client is one that needs an anonymized version of the playback configurations, we
87 // keep track of whether there is at least one to know when we need to create the list of
88 // playback configurations that do not contain uid/pid/package name information.
89 private boolean mHasPublicClients = false;
90
91 private final Object mPlayerLock = new Object();
Andy Hung7da0e982017-02-22 12:34:21 -080092 private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080093 new HashMap<Integer, AudioPlaybackConfiguration>();
94
Eric Laurente5a351c2017-09-27 20:11:51 -070095 private final Context mContext;
96 private int mSavedAlarmVolume = -1;
97 private final int mMaxAlarmVolume;
98 private int mPrivilegedAlarmActiveCount = 0;
99
100 PlaybackActivityMonitor(Context context, int maxAlarmVolume) {
101 mContext = context;
102 mMaxAlarmVolume = maxAlarmVolume;
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800103 PlayMonitorClient.sListenerDeathMonitor = this;
104 AudioPlaybackConfiguration.sPlayerDeathMonitor = this;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800105 }
106
107 //=================================================================
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700108 private final ArrayList<Integer> mBannedUids = new ArrayList<Integer>();
109
110 // see AudioManagerInternal.disableAudioForUid(boolean disable, int uid)
111 public void disableAudioForUid(boolean disable, int uid) {
112 synchronized(mPlayerLock) {
113 final int index = mBannedUids.indexOf(new Integer(uid));
114 if (index >= 0) {
115 if (!disable) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700116 if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700117 sEventLogger.log(new AudioEventLogger.StringEvent("unbanning uid:" + uid));
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700118 }
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700119 mBannedUids.remove(index);
120 // nothing else to do, future playback requests from this uid are ok
121 } // no else to handle, uid already present, so disabling again is no-op
122 } else {
123 if (disable) {
124 for (AudioPlaybackConfiguration apc : mPlayers.values()) {
125 checkBanPlayer(apc, uid);
126 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700127 if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700128 sEventLogger.log(new AudioEventLogger.StringEvent("banning uid:" + uid));
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700129 }
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700130 mBannedUids.add(new Integer(uid));
131 } // no else to handle, uid already not in list, so enabling again is no-op
132 }
133 }
134 }
135
136 private boolean checkBanPlayer(@NonNull AudioPlaybackConfiguration apc, int uid) {
137 final boolean toBan = (apc.getClientUid() == uid);
138 if (toBan) {
139 final int piid = apc.getPlayerInterfaceId();
140 try {
141 Log.v(TAG, "banning player " + piid + " uid:" + uid);
142 apc.getPlayerProxy().pause();
143 } catch (Exception e) {
144 Log.e(TAG, "error banning player " + piid + " uid:" + uid, e);
145 }
146 }
147 return toBan;
148 }
149
150 //=================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800151 // Track players and their states
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800152 // methods playerAttributes, playerEvent, releasePlayer are all oneway calls
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800153 // into AudioService. They trigger synchronous dispatchPlaybackChange() which updates
154 // all listeners as oneway calls.
155
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800156 public int trackPlayer(PlayerBase.PlayerIdCard pic) {
157 final int newPiid = AudioSystem.newAudioPlayerId();
158 if (DEBUG) { Log.v(TAG, "trackPlayer() new piid=" + newPiid); }
159 final AudioPlaybackConfiguration apc =
160 new AudioPlaybackConfiguration(pic, newPiid,
161 Binder.getCallingUid(), Binder.getCallingPid());
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800162 apc.init();
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700163 sEventLogger.log(new NewPlayerEvent(apc));
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800164 synchronized(mPlayerLock) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800165 mPlayers.put(newPiid, apc);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800166 }
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800167 return newPiid;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800168 }
169
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800170 public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800171 final boolean change;
172 synchronized(mPlayerLock) {
173 final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800174 if (checkConfigurationCaller(piid, apc, binderUid)) {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700175 sEventLogger.log(new AudioAttrEvent(piid, attr));
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800176 change = apc.handleAudioAttributesEvent(attr);
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800177 } else {
178 Log.e(TAG, "Error updating audio attributes");
179 change = false;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800180 }
181 }
182 if (change) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700183 dispatchPlaybackChange(false);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800184 }
185 }
186
Jean-Michel Trivid51d3982017-10-10 16:32:38 -0700187 private static final int FLAGS_FOR_SILENCE_OVERRIDE =
188 AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
189 AudioAttributes.FLAG_BYPASS_MUTE;
190
Eric Laurente5a351c2017-09-27 20:11:51 -0700191 private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) {
192 if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED ||
193 apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
Jean-Michel Trivid51d3982017-10-10 16:32:38 -0700194 if ((apc.getAudioAttributes().getAllFlags() & FLAGS_FOR_SILENCE_OVERRIDE)
195 == FLAGS_FOR_SILENCE_OVERRIDE &&
Eric Laurente5a351c2017-09-27 20:11:51 -0700196 apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM &&
197 mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
198 apc.getClientPid(), apc.getClientUid()) ==
199 PackageManager.PERMISSION_GRANTED) {
200 if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
201 apc.getPlayerState() != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
202 if (mPrivilegedAlarmActiveCount++ == 0) {
203 mSavedAlarmVolume = AudioSystem.getStreamVolumeIndex(
204 AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER);
205 AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
206 mMaxAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
207 }
208 } else if (event != AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
209 apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
210 if (--mPrivilegedAlarmActiveCount == 0) {
211 if (AudioSystem.getStreamVolumeIndex(
212 AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER) ==
213 mMaxAlarmVolume) {
214 AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
215 mSavedAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
216 }
217 }
218 }
219 }
220 }
221 }
222
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800223 public void playerEvent(int piid, int event, int binderUid) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800224 if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800225 final boolean change;
226 synchronized(mPlayerLock) {
227 final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700228 if (apc == null) {
229 return;
230 }
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700231 sEventLogger.log(new PlayerEvent(piid, event));
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700232 if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
233 for (Integer uidInteger: mBannedUids) {
234 if (checkBanPlayer(apc, uidInteger.intValue())) {
235 // player was banned, do not update its state
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700236 sEventLogger.log(new AudioEventLogger.StringEvent(
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700237 "not starting piid:" + piid + " ,is banned"));
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700238 return;
239 }
240 }
241 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700242 if (apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
243 // FIXME SoundPool not ready for state reporting
Jean-Michel Trivif1d82762017-02-14 14:24:37 -0800244 return;
245 }
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800246 if (checkConfigurationCaller(piid, apc, binderUid)) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800247 //TODO add generation counter to only update to the latest state
Eric Laurente5a351c2017-09-27 20:11:51 -0700248 checkVolumeForPrivilegedAlarm(apc, event);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800249 change = apc.handleStateEvent(event);
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800250 } else {
251 Log.e(TAG, "Error handling event " + event);
252 change = false;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800253 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700254 if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
255 mDuckingManager.checkDuck(apc);
Jean-Michel Trivicafed632017-04-03 18:49:45 -0700256 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800257 }
258 if (change) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700259 dispatchPlaybackChange(event == AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800260 }
261 }
262
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -0700263 public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) {
264 // no check on UID yet because this is only for logging at the moment
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700265 sEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -0700266 }
267
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800268 public void releasePlayer(int piid, int binderUid) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800269 if (DEBUG) { Log.v(TAG, "releasePlayer() for piid=" + piid); }
Jean-Michel Trivi2a281262018-04-23 17:22:55 -0700270 boolean change = false;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800271 synchronized(mPlayerLock) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800272 final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
273 if (checkConfigurationCaller(piid, apc, binderUid)) {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700274 sEventLogger.log(new AudioEventLogger.StringEvent(
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700275 "releasing player piid:" + piid));
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800276 mPlayers.remove(new Integer(piid));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700277 mDuckingManager.removeReleased(apc);
Eric Laurente5a351c2017-09-27 20:11:51 -0700278 checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
Jean-Michel Trivi2a281262018-04-23 17:22:55 -0700279 change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800280 }
281 }
Jean-Michel Trivi2a281262018-04-23 17:22:55 -0700282 if (change) {
283 dispatchPlaybackChange(true /*iplayerreleased*/);
284 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800285 }
286
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800287 // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
288 @Override
289 public void playerDeath(int piid) {
290 releasePlayer(piid, 0);
291 }
292
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800293 protected void dump(PrintWriter pw) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800294 // players
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800295 pw.println("\nPlaybackActivityMonitor dump time: "
296 + DateFormat.getTimeInstance().format(new Date()));
297 synchronized(mPlayerLock) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700298 pw.println("\n playback listeners:");
299 synchronized(mClients) {
300 for (PlayMonitorClient pmc : mClients) {
301 pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)")
302 + pmc.toString());
303 }
304 }
305 pw.println("\n");
Jean-Michel Trivi56266192017-07-18 14:53:40 -0700306 // all players
307 pw.println("\n players:");
308 final List<Integer> piidIntList = new ArrayList<Integer>(mPlayers.keySet());
309 Collections.sort(piidIntList);
310 for (Integer piidInt : piidIntList) {
311 final AudioPlaybackConfiguration apc = mPlayers.get(piidInt);
312 if (apc != null) {
313 apc.dump(pw);
314 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800315 }
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800316 // ducked players
Jean-Michel Trivi56266192017-07-18 14:53:40 -0700317 pw.println("\n ducked players piids:");
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700318 mDuckingManager.dump(pw);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800319 // players muted due to the device ringing or being in a call
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700320 pw.print("\n muted player piids:");
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800321 for (int piid : mMutedPlayers) {
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700322 pw.print(" " + piid);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800323 }
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700324 pw.println();
325 // banned players:
326 pw.print("\n banned uids:");
327 for (int uid : mBannedUids) {
328 pw.print(" " + uid);
329 }
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700330 pw.println("\n");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700331 // log
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700332 sEventLogger.dump(pw);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800333 }
334 }
335
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800336 /**
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -0700337 * Check that piid and uid are valid for the given valid configuration.
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800338 * @param piid the piid of the player.
339 * @param apc the configuration found for this piid.
340 * @param binderUid actual uid of client trying to signal a player state/event/attributes.
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -0700341 * @return true if the call is valid and the change should proceed, false otherwise. Always
342 * returns false when apc is null.
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800343 */
344 private static boolean checkConfigurationCaller(int piid,
345 final AudioPlaybackConfiguration apc, int binderUid) {
346 if (apc == null) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -0800347 return false;
348 } else if ((binderUid != 0) && (apc.getClientUid() != binderUid)) {
349 Log.e(TAG, "Forbidden operation from uid " + binderUid + " for player " + piid);
350 return false;
351 }
352 return true;
353 }
354
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700355 /**
356 * Sends new list after update of playback configurations
357 * @param iplayerReleased indicates if the change was due to a player being released
358 */
359 private void dispatchPlaybackChange(boolean iplayerReleased) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800360 synchronized (mClients) {
361 // typical use case, nobody is listening, don't do any work
362 if (mClients.isEmpty()) {
363 return;
364 }
365 }
366 if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
367 final List<AudioPlaybackConfiguration> configsSystem;
368 // list of playback configurations for "public consumption". It is only computed if there
369 // are non-system playback activity listeners.
370 final List<AudioPlaybackConfiguration> configsPublic;
371 synchronized (mPlayerLock) {
372 if (mPlayers.isEmpty()) {
373 return;
374 }
375 configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
376 }
377 synchronized (mClients) {
378 // was done at beginning of method, but could have changed
379 if (mClients.isEmpty()) {
380 return;
381 }
382 configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
383 final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
384 while (clientIterator.hasNext()) {
385 final PlayMonitorClient pmc = clientIterator.next();
386 try {
387 // do not spam the logs if there are problems communicating with this client
388 if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
389 if (pmc.mIsPrivileged) {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700390 pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
391 iplayerReleased);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800392 } else {
Jean-Michel Trivi776a3992017-09-12 16:45:34 -0700393 // non-system clients don't have the control interface IPlayer, so
394 // they don't need to flush commands when a player was released
395 pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800396 }
397 }
398 } catch (RemoteException e) {
399 pmc.mErrorCount++;
400 Log.e(TAG, "Error (" + pmc.mErrorCount +
401 ") trying to dispatch playback config change to " + pmc, e);
402 }
403 }
404 }
405 }
406
407 private ArrayList<AudioPlaybackConfiguration> anonymizeForPublicConsumption(
408 List<AudioPlaybackConfiguration> sysConfigs) {
409 ArrayList<AudioPlaybackConfiguration> publicConfigs =
410 new ArrayList<AudioPlaybackConfiguration>();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800411 // only add active anonymized configurations,
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800412 for (AudioPlaybackConfiguration config : sysConfigs) {
413 if (config.isActive()) {
414 publicConfigs.add(AudioPlaybackConfiguration.anonymizedCopy(config));
415 }
416 }
417 return publicConfigs;
418 }
419
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800420
421 //=================================================================
422 // PlayerFocusEnforcer implementation
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800423 private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700424
425 private final DuckingManager mDuckingManager = new DuckingManager();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800426
427 @Override
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800428 public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800429 if (DEBUG) {
430 Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d",
Jean-Michel Trivicafed632017-04-03 18:49:45 -0700431 winner.getClientUid(), loser.getClientUid()));
432 }
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800433 synchronized (mPlayerLock) {
434 if (mPlayers.isEmpty()) {
435 return true;
436 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700437 // check if this UID needs to be ducked (return false if not), and gather list of
438 // eligible players to duck
439 final Iterator<AudioPlaybackConfiguration> apcIterator = mPlayers.values().iterator();
440 final ArrayList<AudioPlaybackConfiguration> apcsToDuck =
441 new ArrayList<AudioPlaybackConfiguration>();
442 while (apcIterator.hasNext()) {
443 final AudioPlaybackConfiguration apc = apcIterator.next();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800444 if (!winner.hasSameUid(apc.getClientUid())
445 && loser.hasSameUid(apc.getClientUid())
446 && apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED)
447 {
Jean-Michel Trivi9228af62018-01-05 17:06:17 -0800448 if (!forceDuck && (apc.getAudioAttributes().getContentType() ==
449 AudioAttributes.CONTENT_TYPE_SPEECH)) {
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800450 // the player is speaking, ducking will make the speech unintelligible
451 // so let the app handle it instead
Jean-Michel Trivi087b6722017-05-10 13:05:06 -0700452 Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
453 + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
454 + " - SPEECH");
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800455 return false;
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -0700456 } else if (ArrayUtils.contains(UNDUCKABLE_PLAYER_TYPES, apc.getPlayerType())) {
Jean-Michel Trivi087b6722017-05-10 13:05:06 -0700457 Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
458 + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
Jean-Michel Trivi83271bd2017-06-23 18:28:41 -0700459 + " due to type:"
460 + AudioPlaybackConfiguration.toLogFriendlyPlayerType(
461 apc.getPlayerType()));
Jean-Michel Trividce82ab2017-02-07 16:02:33 -0800462 return false;
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800463 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700464 apcsToDuck.add(apc);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800465 }
466 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700467 // add the players eligible for ducking to the list, and duck them
468 // (if apcsToDuck is empty, this will at least mark this uid as ducked, so when
469 // players of the same uid start, they will be ducked by DuckingManager.checkDuck())
470 mDuckingManager.duckUid(loser.getClientUid(), apcsToDuck);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800471 }
472 return true;
473 }
474
475 @Override
476 public void unduckPlayers(FocusRequester winner) {
477 if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
478 synchronized (mPlayerLock) {
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700479 mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800480 }
481 }
482
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800483 @Override
484 public void mutePlayersForCall(int[] usagesToMute) {
485 if (DEBUG) {
486 String log = new String("mutePlayersForCall: usages=");
487 for (int usage : usagesToMute) { log += " " + usage; }
488 Log.v(TAG, log);
489 }
490 synchronized (mPlayerLock) {
491 final Set<Integer> piidSet = mPlayers.keySet();
492 final Iterator<Integer> piidIterator = piidSet.iterator();
493 // find which players to mute
494 while (piidIterator.hasNext()) {
495 final Integer piid = piidIterator.next();
496 final AudioPlaybackConfiguration apc = mPlayers.get(piid);
Jean-Michel Trivibd39cfa2017-02-17 17:23:36 -0800497 if (apc == null) {
498 continue;
499 }
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800500 final int playerUsage = apc.getAudioAttributes().getUsage();
501 boolean mute = false;
502 for (int usageToMute : usagesToMute) {
503 if (playerUsage == usageToMute) {
504 mute = true;
505 break;
506 }
507 }
508 if (mute) {
509 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700510 sEventLogger.log((new AudioEventLogger.StringEvent("call: muting piid:"
511 + piid + " uid:" + apc.getClientUid())).printLog(TAG));
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800512 apc.getPlayerProxy().setVolume(0.0f);
Jean-Michel Trivicafed632017-04-03 18:49:45 -0700513 mMutedPlayers.add(new Integer(piid));
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800514 } catch (Exception e) {
Jean-Michel Trivi952f2342017-03-06 16:16:56 -0800515 Log.e(TAG, "call: error muting player " + piid, e);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800516 }
517 }
518 }
519 }
520 }
521
522 @Override
523 public void unmutePlayersForCall() {
524 if (DEBUG) {
525 Log.v(TAG, "unmutePlayersForCall()");
526 }
527 synchronized (mPlayerLock) {
528 if (mMutedPlayers.isEmpty()) {
529 return;
530 }
531 for (int piid : mMutedPlayers) {
532 final AudioPlaybackConfiguration apc = mPlayers.get(piid);
533 if (apc != null) {
534 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700535 sEventLogger.log(new AudioEventLogger.StringEvent("call: unmuting piid:"
536 + piid).printLog(TAG));
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800537 apc.getPlayerProxy().setVolume(1.0f);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800538 } catch (Exception e) {
Jean-Michel Trivi087b6722017-05-10 13:05:06 -0700539 Log.e(TAG, "call: error unmuting player " + piid + " uid:"
540 + apc.getClientUid(), e);
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800541 }
542 }
543 }
Jean-Michel Trivi579c5112017-02-10 09:47:30 -0800544 mMutedPlayers.clear();
Jean-Michel Trivi62b86342017-02-04 15:33:47 -0800545 }
546 }
547
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800548 //=================================================================
549 // Track playback activity listeners
550
551 void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
552 if (pcdb == null) {
553 return;
554 }
555 synchronized(mClients) {
556 final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
557 if (pmc.init()) {
558 if (!isPrivileged) {
559 mHasPublicClients = true;
560 }
561 mClients.add(pmc);
562 }
563 }
564 }
565
566 void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
567 if (pcdb == null) {
568 return;
569 }
570 synchronized(mClients) {
571 final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
572 boolean hasPublicClients = false;
573 // iterate over the clients to remove the dispatcher to remove, and reevaluate at
574 // the same time if we still have a public client.
575 while (clientIterator.hasNext()) {
576 PlayMonitorClient pmc = clientIterator.next();
577 if (pcdb.equals(pmc.mDispatcherCb)) {
578 pmc.release();
579 clientIterator.remove();
580 } else {
581 if (!pmc.mIsPrivileged) {
582 hasPublicClients = true;
583 }
584 }
585 }
586 mHasPublicClients = hasPublicClients;
587 }
588 }
589
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800590 List<AudioPlaybackConfiguration> getActivePlaybackConfigurations(boolean isPrivileged) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800591 synchronized(mPlayers) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -0800592 if (isPrivileged) {
593 return new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
594 } else {
595 final List<AudioPlaybackConfiguration> configsPublic;
596 synchronized (mPlayerLock) {
597 configsPublic = anonymizeForPublicConsumption(
598 new ArrayList<AudioPlaybackConfiguration>(mPlayers.values()));
599 }
600 return configsPublic;
601 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800602 }
603 }
604
605
606 /**
607 * Inner class to track clients that want to be notified of playback updates
608 */
Jean-Michel Trivic2769ab2017-04-24 11:59:29 -0700609 private static final class PlayMonitorClient implements IBinder.DeathRecipient {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800610
611 // can afford to be static because only one PlaybackActivityMonitor ever instantiated
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800612 static PlaybackActivityMonitor sListenerDeathMonitor;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800613
614 final IPlaybackConfigDispatcher mDispatcherCb;
615 final boolean mIsPrivileged;
616
617 int mErrorCount = 0;
618 // number of errors after which we don't update this client anymore to not spam the logs
619 static final int MAX_ERRORS = 5;
620
621 PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
622 mDispatcherCb = pcdb;
623 mIsPrivileged = isPrivileged;
624 }
625
626 public void binderDied() {
627 Log.w(TAG, "client died");
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800628 sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800629 }
630
631 boolean init() {
632 try {
633 mDispatcherCb.asBinder().linkToDeath(this, 0);
634 return true;
635 } catch (RemoteException e) {
636 Log.w(TAG, "Could not link to client death", e);
637 return false;
638 }
639 }
640
641 void release() {
642 mDispatcherCb.asBinder().unlinkToDeath(this, 0);
643 }
644 }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700645
646 //=================================================================
647 // Class to handle ducking related operations for a given UID
648 private static final class DuckingManager {
649 private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
650
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700651 synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
652 if (DEBUG) { Log.v(TAG, "DuckingManager: duckUid() uid:"+ uid); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700653 if (!mDuckers.containsKey(uid)) {
654 mDuckers.put(uid, new DuckedApp(uid));
655 }
656 final DuckedApp da = mDuckers.get(uid);
657 for (AudioPlaybackConfiguration apc : apcsToDuck) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700658 da.addDuck(apc, false /*skipRamp*/);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700659 }
660 }
661
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700662 synchronized void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
663 if (DEBUG) { Log.v(TAG, "DuckingManager: unduckUid() uid:"+ uid); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700664 final DuckedApp da = mDuckers.remove(uid);
665 if (da == null) {
666 return;
667 }
668 da.removeUnduckAll(players);
669 }
670
671 // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700672 synchronized void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
673 if (DEBUG) { Log.v(TAG, "DuckingManager: checkDuck() player piid:"
674 + apc.getPlayerInterfaceId()+ " uid:"+ apc.getClientUid()); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700675 final DuckedApp da = mDuckers.get(apc.getClientUid());
676 if (da == null) {
677 return;
678 }
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700679 da.addDuck(apc, true /*skipRamp*/);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700680 }
681
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700682 synchronized void dump(PrintWriter pw) {
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700683 for (DuckedApp da : mDuckers.values()) {
684 da.dump(pw);
685 }
686 }
687
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700688 synchronized void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
689 final int uid = apc.getClientUid();
690 if (DEBUG) { Log.v(TAG, "DuckingManager: removedReleased() player piid: "
691 + apc.getPlayerInterfaceId() + " uid:" + uid); }
692 final DuckedApp da = mDuckers.get(uid);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700693 if (da == null) {
694 return;
695 }
696 da.removeReleased(apc);
697 }
698
699 private static final class DuckedApp {
700 private final int mUid;
701 private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
702
703 DuckedApp(int uid) {
704 mUid = uid;
705 }
706
707 void dump(PrintWriter pw) {
708 pw.print("\t uid:" + mUid + " piids:");
709 for (int piid : mDuckedPlayers) {
710 pw.print(" " + piid);
711 }
712 pw.println("");
713 }
714
715 // pre-conditions:
716 // * apc != null
717 // * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700718 void addDuck(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700719 final int piid = new Integer(apc.getPlayerInterfaceId());
720 if (mDuckedPlayers.contains(piid)) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700721 if (DEBUG) { Log.v(TAG, "player piid:" + piid + " already ducked"); }
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700722 return;
723 }
724 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700725 sEventLogger.log((new DuckEvent(apc, skipRamp)).printLog(TAG));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700726 apc.getPlayerProxy().applyVolumeShaper(
727 DUCK_VSHAPE,
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700728 skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700729 mDuckedPlayers.add(piid);
730 } catch (Exception e) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700731 Log.e(TAG, "Error ducking player piid:" + piid + " uid:" + mUid, e);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700732 }
733 }
734
735 void removeUnduckAll(HashMap<Integer, AudioPlaybackConfiguration> players) {
736 for (int piid : mDuckedPlayers) {
737 final AudioPlaybackConfiguration apc = players.get(piid);
738 if (apc != null) {
739 try {
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700740 sEventLogger.log((new AudioEventLogger.StringEvent("unducking piid:"
741 + piid)).printLog(TAG));
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700742 apc.getPlayerProxy().applyVolumeShaper(
743 DUCK_ID,
744 VolumeShaper.Operation.REVERSE);
745 } catch (Exception e) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700746 Log.e(TAG, "Error unducking player piid:" + piid + " uid:" + mUid, e);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700747 }
748 } else {
749 // this piid was in the list of ducked players, but wasn't found
750 if (DEBUG) {
Jean-Michel Trivi2e48fb52017-05-16 17:59:54 -0700751 Log.v(TAG, "Error unducking player piid:" + piid
752 + ", player not found for uid " + mUid);
Jean-Michel Trivicb84fc02017-05-03 12:16:17 -0700753 }
754 }
755 }
756 mDuckedPlayers.clear();
757 }
758
759 void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
760 mDuckedPlayers.remove(new Integer(apc.getPlayerInterfaceId()));
761 }
762 }
763 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700764
765 //=================================================================
766 // For logging
767 private final static class PlayerEvent extends AudioEventLogger.Event {
768 // only keeping the player interface ID as it uniquely identifies the player in the event
769 final int mPlayerIId;
770 final int mState;
771
772 PlayerEvent(int piid, int state) {
773 mPlayerIId = piid;
774 mState = state;
775 }
776
777 @Override
778 public String eventToString() {
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -0700779 return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
780 .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
781 }
782 }
783
784 private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event {
785 // only keeping the player interface ID as it uniquely identifies the player in the event
786 final int mPlayerIId;
787 final boolean mHasOp;
788 final int mUid;
789
790 PlayerOpPlayAudioEvent(int piid, boolean hasOp, int uid) {
791 mPlayerIId = piid;
792 mHasOp = hasOp;
793 mUid = uid;
794 }
795
796 @Override
797 public String eventToString() {
798 return new StringBuilder("player piid:").append(mPlayerIId)
799 .append(" has OP_PLAY_AUDIO:").append(mHasOp)
800 .append(" in uid:").append(mUid).toString();
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700801 }
802 }
803
804 private final static class NewPlayerEvent extends AudioEventLogger.Event {
805 private final int mPlayerIId;
806 private final int mPlayerType;
807 private final int mClientUid;
808 private final int mClientPid;
809 private final AudioAttributes mPlayerAttr;
810
811 NewPlayerEvent(AudioPlaybackConfiguration apc) {
812 mPlayerIId = apc.getPlayerInterfaceId();
813 mPlayerType = apc.getPlayerType();
814 mClientUid = apc.getClientUid();
815 mClientPid = apc.getClientPid();
816 mPlayerAttr = apc.getAudioAttributes();
817 }
818
819 @Override
820 public String eventToString() {
821 return new String("new player piid:" + mPlayerIId + " uid/pid:" + mClientUid + "/"
822 + mClientPid + " type:"
823 + AudioPlaybackConfiguration.toLogFriendlyPlayerType(mPlayerType)
824 + " attr:" + mPlayerAttr);
825 }
826 }
827
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700828 private static final class DuckEvent extends AudioEventLogger.Event {
829 private final int mPlayerIId;
830 private final boolean mSkipRamp;
831 private final int mClientUid;
832 private final int mClientPid;
833
834 DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
835 mPlayerIId = apc.getPlayerInterfaceId();
836 mSkipRamp = skipRamp;
837 mClientUid = apc.getClientUid();
838 mClientPid = apc.getClientPid();
839 }
840
841 @Override
842 public String eventToString() {
843 return new StringBuilder("ducking player piid:").append(mPlayerIId)
844 .append(" uid/pid:").append(mClientUid).append("/").append(mClientPid)
845 .append(" skip ramp:").append(mSkipRamp).toString();
846 }
847 }
848
849 private static final class AudioAttrEvent extends AudioEventLogger.Event {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700850 private final int mPlayerIId;
851 private final AudioAttributes mPlayerAttr;
852
853 AudioAttrEvent(int piid, AudioAttributes attr) {
854 mPlayerIId = piid;
855 mPlayerAttr = attr;
856 }
857
858 @Override
859 public String eventToString() {
860 return new String("player piid:" + mPlayerIId + " new AudioAttributes:" + mPlayerAttr);
861 }
862 }
863
Jean-Michel Trivi74a55962017-10-02 17:46:18 -0700864 private static final AudioEventLogger sEventLogger = new AudioEventLogger(100,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700865 "playback activity as reported through PlayerBase");
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800866}