1292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi/*
2292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * Copyright (C) 2016 The Android Open Source Project
3292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi *
4292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
5292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * you may not use this file except in compliance with the License.
6292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * You may obtain a copy of the License at
7292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi *
8292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
9292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi *
10292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
11292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
12292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * See the License for the specific language governing permissions and
14292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * limitations under the License.
15292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi */
16292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
17292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivipackage com.android.server.audio;
18292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
19292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.annotation.NonNull;
20e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurentimport android.content.Context;
21e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurentimport android.content.pm.PackageManager;
22292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.media.AudioAttributes;
23292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.media.AudioManager;
24292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.media.AudioPlaybackConfiguration;
25292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.media.AudioSystem;
26292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.media.IPlaybackConfigDispatcher;
27292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.media.PlayerBase;
28dce82ab7bfd5ec7c1ef658825c18506a89e567d6Jean-Michel Triviimport android.media.VolumeShaper;
2944a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Triviimport android.os.Binder;
30292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.os.IBinder;
31292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.os.RemoteException;
32292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport android.util.Log;
33292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
3483271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Triviimport com.android.internal.util.ArrayUtils;
3583271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi
36292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.io.PrintWriter;
37292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.text.DateFormat;
38292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.util.ArrayList;
3956266190e8d74bcf1d5525634f50368efb845676Jean-Michel Triviimport java.util.Collections;
40292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.util.Date;
41292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.util.HashMap;
42292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.util.Iterator;
43292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Triviimport java.util.List;
4499489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Triviimport java.util.Set;
45292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
46292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi/**
47292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi * Class to receive and dispatch updates from AudioSystem about recording configurations.
48292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi */
499dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivipublic final class PlaybackActivityMonitor
5099489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
51292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
52c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    public static final String TAG = "AudioService.PlaybackActivityMonitor";
530f49f82e9777b7878fbc4566779dbe29191141baJean-Michel Trivi
54c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    private static final boolean DEBUG = false;
55c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    private static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
56292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
57c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    private static final VolumeShaper.Configuration DUCK_VSHAPE =
587da0e98219501cb5ab49331878c7b2cdde541497Andy Hung            new VolumeShaper.Configuration.Builder()
597da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                .setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
607da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                .setCurve(new float[] { 0.f, 1.f } /* times */,
617da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                    new float[] { 1.f, 0.2f } /* volumes */)
627da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                .setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
634c86efa1e3fd8f467f4053b8027a9db12eee584cJean-Michel Trivi                .setDuration(MediaFocusControl.getFocusRampTimeMs(
647da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
657da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                    new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
667da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                            .build()))
677da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                .build();
68c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    private static final VolumeShaper.Configuration DUCK_ID =
697da0e98219501cb5ab49331878c7b2cdde541497Andy Hung            new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
70c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    private static final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
717da0e98219501cb5ab49331878c7b2cdde541497Andy Hung            new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
727da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                    .createIfNeeded()
737da0e98219501cb5ab49331878c7b2cdde541497Andy Hung                    .build();
747da0e98219501cb5ab49331878c7b2cdde541497Andy Hung
7583271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi    // TODO support VolumeShaper on those players
7683271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi    private static final int[] UNDUCKABLE_PLAYER_TYPES = {
7783271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi            AudioPlaybackConfiguration.PLAYER_TYPE_AAUDIO,
7883271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi            AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL,
7983271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi    };
8083271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi
812e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi    // like a PLAY_CREATE_IF_NEEDED operation but with a skip to the end of the ramp
822e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi    private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
832e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
842e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi
857da0e98219501cb5ab49331878c7b2cdde541497Andy Hung    private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
86292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    // a public client is one that needs an anonymized version of the playback configurations, we
87292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    // keep track of whether there is at least one to know when we need to create the list of
88292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    // playback configurations that do not contain uid/pid/package name information.
89292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    private boolean mHasPublicClients = false;
90292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
91292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    private final Object mPlayerLock = new Object();
927da0e98219501cb5ab49331878c7b2cdde541497Andy Hung    private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
93292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            new HashMap<Integer, AudioPlaybackConfiguration>();
94292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
95e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    private final Context mContext;
96e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    private int mSavedAlarmVolume = -1;
97e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    private final int mMaxAlarmVolume;
98e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    private int mPrivilegedAlarmActiveCount = 0;
99e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent
100e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    PlaybackActivityMonitor(Context context, int maxAlarmVolume) {
101e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent        mContext = context;
102e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent        mMaxAlarmVolume = maxAlarmVolume;
1039dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi        PlayMonitorClient.sListenerDeathMonitor = this;
1049dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi        AudioPlaybackConfiguration.sPlayerDeathMonitor = this;
105292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
106292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
107292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    //=================================================================
10892ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    private final ArrayList<Integer> mBannedUids = new ArrayList<Integer>();
10992ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi
11092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    // see AudioManagerInternal.disableAudioForUid(boolean disable, int uid)
11192ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    public void disableAudioForUid(boolean disable, int uid) {
11292ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi        synchronized(mPlayerLock) {
11392ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            final int index = mBannedUids.indexOf(new Integer(uid));
11492ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            if (index >= 0) {
11592ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                if (!disable) {
116011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
11774a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                        sEventLogger.log(new AudioEventLogger.StringEvent("unbanning uid:" + uid));
118011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    }
11992ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    mBannedUids.remove(index);
12092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    // nothing else to do, future playback requests from this uid are ok
12192ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                } // no else to handle, uid already present, so disabling again is no-op
12292ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            } else {
12392ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                if (disable) {
12492ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    for (AudioPlaybackConfiguration apc : mPlayers.values()) {
12592ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                        checkBanPlayer(apc, uid);
12692ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    }
127011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    if (DEBUG) { // hidden behind DEBUG, too noisy otherwise
12874a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                        sEventLogger.log(new AudioEventLogger.StringEvent("banning uid:" + uid));
129011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    }
13092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    mBannedUids.add(new Integer(uid));
13192ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                } // no else to handle, uid already not in list, so enabling again is no-op
13292ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            }
13392ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi        }
13492ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    }
13592ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi
13692ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    private boolean checkBanPlayer(@NonNull AudioPlaybackConfiguration apc, int uid) {
13792ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi        final boolean toBan = (apc.getClientUid() == uid);
13892ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi        if (toBan) {
13992ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            final int piid = apc.getPlayerInterfaceId();
14092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            try {
14192ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                Log.v(TAG, "banning player " + piid + " uid:" + uid);
14292ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                apc.getPlayerProxy().pause();
14392ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            } catch (Exception e) {
14492ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                Log.e(TAG, "error banning player " + piid + " uid:" + uid, e);
14592ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            }
14692ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi        }
14792ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi        return toBan;
14892ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    }
14992ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi
15092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi    //=================================================================
151292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    // Track players and their states
15244a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi    // methods playerAttributes, playerEvent, releasePlayer are all oneway calls
153292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    //  into AudioService. They trigger synchronous dispatchPlaybackChange() which updates
154292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    //  all listeners as oneway calls.
155292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
15644a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi    public int trackPlayer(PlayerBase.PlayerIdCard pic) {
15744a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi        final int newPiid = AudioSystem.newAudioPlayerId();
15844a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi        if (DEBUG) { Log.v(TAG, "trackPlayer() new piid=" + newPiid); }
15944a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi        final AudioPlaybackConfiguration apc =
16044a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                new AudioPlaybackConfiguration(pic, newPiid,
16144a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                        Binder.getCallingUid(), Binder.getCallingPid());
1629dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi        apc.init();
16374a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        sEventLogger.log(new NewPlayerEvent(apc));
164292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mPlayerLock) {
16544a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi            mPlayers.put(newPiid, apc);
166292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
16744a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi        return newPiid;
168292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
169292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
17046e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi    public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
171292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        final boolean change;
172292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mPlayerLock) {
173292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
17446e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            if (checkConfigurationCaller(piid, apc, binderUid)) {
17574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                sEventLogger.log(new AudioAttrEvent(piid, attr));
176292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                change = apc.handleAudioAttributesEvent(attr);
17746e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            } else {
17846e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi                Log.e(TAG, "Error updating audio attributes");
17946e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi                change = false;
180292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
181292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
182292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        if (change) {
183776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            dispatchPlaybackChange(false);
184292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
185292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
186292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
187d51d398383c99aa0e1c84e46aafa593006d5120dJean-Michel Trivi    private static final int FLAGS_FOR_SILENCE_OVERRIDE =
188d51d398383c99aa0e1c84e46aafa593006d5120dJean-Michel Trivi            AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
189d51d398383c99aa0e1c84e46aafa593006d5120dJean-Michel Trivi            AudioAttributes.FLAG_BYPASS_MUTE;
190d51d398383c99aa0e1c84e46aafa593006d5120dJean-Michel Trivi
191e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    private void checkVolumeForPrivilegedAlarm(AudioPlaybackConfiguration apc, int event) {
192e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent        if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED ||
193e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
194d51d398383c99aa0e1c84e46aafa593006d5120dJean-Michel Trivi            if ((apc.getAudioAttributes().getAllFlags() & FLAGS_FOR_SILENCE_OVERRIDE)
195d51d398383c99aa0e1c84e46aafa593006d5120dJean-Michel Trivi                        == FLAGS_FOR_SILENCE_OVERRIDE  &&
196e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                    apc.getAudioAttributes().getUsage() == AudioAttributes.USAGE_ALARM &&
197e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                    mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
198e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                            apc.getClientPid(), apc.getClientUid()) ==
199e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                            PackageManager.PERMISSION_GRANTED) {
200e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
201e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                        apc.getPlayerState() != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
202e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                    if (mPrivilegedAlarmActiveCount++ == 0) {
203e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                        mSavedAlarmVolume = AudioSystem.getStreamVolumeIndex(
204e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                                AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER);
205e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                        AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
206e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                                mMaxAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
207e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                    }
208e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                } else if (event != AudioPlaybackConfiguration.PLAYER_STATE_STARTED &&
209e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                        apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
210e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                    if (--mPrivilegedAlarmActiveCount == 0) {
211e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                        if (AudioSystem.getStreamVolumeIndex(
212e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                                AudioSystem.STREAM_ALARM, AudioSystem.DEVICE_OUT_SPEAKER) ==
213e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                                mMaxAlarmVolume) {
214e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                            AudioSystem.setStreamVolumeIndex(AudioSystem.STREAM_ALARM,
215e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                                    mSavedAlarmVolume, AudioSystem.DEVICE_OUT_SPEAKER);
216e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                        }
217e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                    }
218e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                }
219e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent            }
220e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent        }
221e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent    }
222e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent
22346e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi    public void playerEvent(int piid, int event, int binderUid) {
22444a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi        if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
225292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        final boolean change;
226292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mPlayerLock) {
227292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
228cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (apc == null) {
229cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                return;
230cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
23174a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            sEventLogger.log(new PlayerEvent(piid, event));
23292ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
23392ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                for (Integer uidInteger: mBannedUids) {
23492ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    if (checkBanPlayer(apc, uidInteger.intValue())) {
23592ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                        // player was banned, do not update its state
23674a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                        sEventLogger.log(new AudioEventLogger.StringEvent(
237011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                                "not starting piid:" + piid + " ,is banned"));
23892ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                        return;
23992ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                    }
24092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                }
24192ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            }
242cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
243cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                // FIXME SoundPool not ready for state reporting
244f1d82761ee0a4a0bb32a565f01127534cc9ab7dbJean-Michel Trivi                return;
245f1d82761ee0a4a0bb32a565f01127534cc9ab7dbJean-Michel Trivi            }
24646e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            if (checkConfigurationCaller(piid, apc, binderUid)) {
247292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                //TODO add generation counter to only update to the latest state
248e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                checkVolumeForPrivilegedAlarm(apc, event);
249292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                change = apc.handleStateEvent(event);
25046e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            } else {
25146e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi                Log.e(TAG, "Error handling event " + event);
25246e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi                change = false;
253292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
254cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
255cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                mDuckingManager.checkDuck(apc);
256cafed63e3acfebe1c633433c9e3a6013bb1f47ccJean-Michel Trivi            }
257292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
258292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        if (change) {
259776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            dispatchPlaybackChange(event == AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
260292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
261292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
262292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
2633120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi    public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) {
2643120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        // no check on UID yet because this is only for logging at the moment
26574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        sEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
2663120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi    }
2673120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi
26846e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi    public void releasePlayer(int piid, int binderUid) {
269292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        if (DEBUG) { Log.v(TAG, "releasePlayer() for piid=" + piid); }
2702a28126af931554a8621341149b86cc54773c71aJean-Michel Trivi        boolean change = false;
271292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mPlayerLock) {
27246e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
27346e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            if (checkConfigurationCaller(piid, apc, binderUid)) {
27474a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                sEventLogger.log(new AudioEventLogger.StringEvent(
275011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                        "releasing player piid:" + piid));
276292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                mPlayers.remove(new Integer(piid));
277cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                mDuckingManager.removeReleased(apc);
278e5a351cb9213b59026efd602011a4d9e99c85649Eric Laurent                checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
2792a28126af931554a8621341149b86cc54773c71aJean-Michel Trivi                change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
280292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
281292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
2822a28126af931554a8621341149b86cc54773c71aJean-Michel Trivi        if (change) {
2832a28126af931554a8621341149b86cc54773c71aJean-Michel Trivi            dispatchPlaybackChange(true /*iplayerreleased*/);
2842a28126af931554a8621341149b86cc54773c71aJean-Michel Trivi        }
285292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
286292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
2879dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi    // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
2889dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi    @Override
2899dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi    public void playerDeath(int piid) {
2909dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi        releasePlayer(piid, 0);
2919dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi    }
2929dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi
293292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    protected void dump(PrintWriter pw) {
29499489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        // players
295292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        pw.println("\nPlaybackActivityMonitor dump time: "
296292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                + DateFormat.getTimeInstance().format(new Date()));
297292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mPlayerLock) {
298776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            pw.println("\n  playback listeners:");
299776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            synchronized(mClients) {
300776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                for (PlayMonitorClient pmc : mClients) {
301776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                    pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)")
302776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                            + pmc.toString());
303776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                }
304776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            }
305776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            pw.println("\n");
30656266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi            // all players
30756266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi            pw.println("\n  players:");
30856266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi            final List<Integer> piidIntList = new ArrayList<Integer>(mPlayers.keySet());
30956266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi            Collections.sort(piidIntList);
31056266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi            for (Integer piidInt : piidIntList) {
31156266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi                final AudioPlaybackConfiguration apc = mPlayers.get(piidInt);
31256266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi                if (apc != null) {
31356266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi                    apc.dump(pw);
31456266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi                }
315292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
31699489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi            // ducked players
31756266190e8d74bcf1d5525634f50368efb845676Jean-Michel Trivi            pw.println("\n  ducked players piids:");
318cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            mDuckingManager.dump(pw);
31962b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            // players muted due to the device ringing or being in a call
32092ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            pw.print("\n  muted player piids:");
32162b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            for (int piid : mMutedPlayers) {
32292ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                pw.print(" " + piid);
32392ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            }
32492ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            pw.println();
32592ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            // banned players:
32692ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            pw.print("\n  banned uids:");
32792ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi            for (int uid : mBannedUids) {
32892ed7bf41235c95b2c71648a631ce7aaa65f8943Jean-Michel Trivi                pw.print(" " + uid);
32962b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            }
330776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi            pw.println("\n");
331011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            // log
33274a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            sEventLogger.dump(pw);
333292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
334292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
335292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
33646e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi    /**
337c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi     * Check that piid and uid are valid for the given valid configuration.
33846e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi     * @param piid the piid of the player.
33946e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi     * @param apc the configuration found for this piid.
34046e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi     * @param binderUid actual uid of client trying to signal a player state/event/attributes.
341c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi     * @return true if the call is valid and the change should proceed, false otherwise. Always
342c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi     *      returns false when apc is null.
34346e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi     */
34446e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi    private static boolean checkConfigurationCaller(int piid,
34546e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            final AudioPlaybackConfiguration apc, int binderUid) {
34646e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi        if (apc == null) {
34746e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            return false;
34846e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi        } else if ((binderUid != 0) && (apc.getClientUid() != binderUid)) {
34946e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            Log.e(TAG, "Forbidden operation from uid " + binderUid + " for player " + piid);
35046e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi            return false;
35146e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi        }
35246e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi        return true;
35346e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi    }
35446e310b34f73fe87a6dd1e7357b486f1cf7cacbcJean-Michel Trivi
355776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi    /**
356776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi     * Sends new list after update of playback configurations
357776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi     * @param iplayerReleased indicates if the change was due to a player being released
358776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi     */
359776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi    private void dispatchPlaybackChange(boolean iplayerReleased) {
360292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized (mClients) {
361292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            // typical use case, nobody is listening, don't do any work
362292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            if (mClients.isEmpty()) {
363292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                return;
364292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
365292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
366292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
367292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        final List<AudioPlaybackConfiguration> configsSystem;
368292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        // list of playback configurations for "public consumption". It is only computed if there
369292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        // are non-system playback activity listeners.
370292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        final List<AudioPlaybackConfiguration> configsPublic;
371292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized (mPlayerLock) {
372292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            if (mPlayers.isEmpty()) {
373292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                return;
374292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
375292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
376292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
377292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized (mClients) {
378292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            // was done at beginning of method, but could have changed
379292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            if (mClients.isEmpty()) {
380292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                return;
381292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
382292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
383292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
384292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            while (clientIterator.hasNext()) {
385292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                final PlayMonitorClient pmc = clientIterator.next();
386292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                try {
387292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    // do not spam the logs if there are problems communicating with this client
388292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
389292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                        if (pmc.mIsPrivileged) {
390776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                            pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
391776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                                    iplayerReleased);
392292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                        } else {
393776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                            // non-system clients don't have the control interface IPlayer, so
394776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                            // they don't need to flush commands when a player was released
395776a39931499d7d118eba916aba017032cde49a9Jean-Michel Trivi                            pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
396292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                        }
397292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    }
398292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                } catch (RemoteException e) {
399292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    pmc.mErrorCount++;
400292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    Log.e(TAG, "Error (" + pmc.mErrorCount +
401292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                            ") trying to dispatch playback config change to " + pmc, e);
402292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                }
403292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
404292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
405292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
406292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
407292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    private ArrayList<AudioPlaybackConfiguration> anonymizeForPublicConsumption(
408292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            List<AudioPlaybackConfiguration> sysConfigs) {
409292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        ArrayList<AudioPlaybackConfiguration> publicConfigs =
410292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                new ArrayList<AudioPlaybackConfiguration>();
41199489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        // only add active anonymized configurations,
412292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        for (AudioPlaybackConfiguration config : sysConfigs) {
413292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            if (config.isActive()) {
414292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                publicConfigs.add(AudioPlaybackConfiguration.anonymizedCopy(config));
415292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
416292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
417292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        return publicConfigs;
418292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
419292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
42099489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi
42199489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    //=================================================================
42299489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    // PlayerFocusEnforcer implementation
42362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
424cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
425cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi    private final DuckingManager mDuckingManager = new DuckingManager();
42699489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi
42799489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    @Override
4289228af6bc20c27b9949df36684f9c06ca9cdb27dJean-Michel Trivi    public boolean duckPlayers(FocusRequester winner, FocusRequester loser, boolean forceDuck) {
42999489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        if (DEBUG) {
43099489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi            Log.v(TAG, String.format("duckPlayers: uids winner=%d loser=%d",
431cafed63e3acfebe1c633433c9e3a6013bb1f47ccJean-Michel Trivi                    winner.getClientUid(), loser.getClientUid()));
432cafed63e3acfebe1c633433c9e3a6013bb1f47ccJean-Michel Trivi        }
43399489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        synchronized (mPlayerLock) {
43499489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi            if (mPlayers.isEmpty()) {
43599489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                return true;
43699489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi            }
437cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            // check if this UID needs to be ducked (return false if not), and gather list of
438cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            // eligible players to duck
439cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            final Iterator<AudioPlaybackConfiguration> apcIterator = mPlayers.values().iterator();
440cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            final ArrayList<AudioPlaybackConfiguration> apcsToDuck =
441cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    new ArrayList<AudioPlaybackConfiguration>();
442cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            while (apcIterator.hasNext()) {
443cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                final AudioPlaybackConfiguration apc = apcIterator.next();
44499489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                if (!winner.hasSameUid(apc.getClientUid())
44599489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                        && loser.hasSameUid(apc.getClientUid())
44699489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                        && apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED)
44799489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                {
4489228af6bc20c27b9949df36684f9c06ca9cdb27dJean-Michel Trivi                    if (!forceDuck && (apc.getAudioAttributes().getContentType() ==
4499228af6bc20c27b9949df36684f9c06ca9cdb27dJean-Michel Trivi                            AudioAttributes.CONTENT_TYPE_SPEECH)) {
45099489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                        // the player is speaking, ducking will make the speech unintelligible
45199489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                        // so let the app handle it instead
452087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                        Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
453087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                                + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
454087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                                + " - SPEECH");
45599489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                        return false;
45683271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi                    } else if (ArrayUtils.contains(UNDUCKABLE_PLAYER_TYPES, apc.getPlayerType())) {
457087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                        Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
458087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                                + " uid:" + apc.getClientUid() + " pid:" + apc.getClientPid()
45983271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi                                + " due to type:"
46083271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi                                + AudioPlaybackConfiguration.toLogFriendlyPlayerType(
46183271bd70e21d420e1258d2473e7b4594915a48fJean-Michel Trivi                                        apc.getPlayerType()));
462dce82ab7bfd5ec7c1ef658825c18506a89e567d6Jean-Michel Trivi                        return false;
46399489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                    }
464cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    apcsToDuck.add(apc);
46599489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi                }
46699489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi            }
467cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            // add the players eligible for ducking to the list, and duck them
468cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            // (if apcsToDuck is empty, this will at least mark this uid as ducked, so when
469cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            //  players of the same uid start, they will be ducked by DuckingManager.checkDuck())
470cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            mDuckingManager.duckUid(loser.getClientUid(), apcsToDuck);
47199489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        }
47299489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        return true;
47399489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    }
47499489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi
47599489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    @Override
47699489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    public void unduckPlayers(FocusRequester winner) {
47799489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
47899489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        synchronized (mPlayerLock) {
479cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
48099489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi        }
48199489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi    }
48299489ccf740d369193a8ffc7eeb4bbde6919bd65Jean-Michel Trivi
48362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    @Override
48462b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    public void mutePlayersForCall(int[] usagesToMute) {
48562b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        if (DEBUG) {
48662b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            String log = new String("mutePlayersForCall: usages=");
48762b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            for (int usage : usagesToMute) { log += " " + usage; }
48862b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            Log.v(TAG, log);
48962b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        }
49062b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        synchronized (mPlayerLock) {
49162b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            final Set<Integer> piidSet = mPlayers.keySet();
49262b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            final Iterator<Integer> piidIterator = piidSet.iterator();
49362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            // find which players to mute
49462b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            while (piidIterator.hasNext()) {
49562b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                final Integer piid = piidIterator.next();
49662b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
497bd39cfaf97106bb8b9ea702d8e1cd5965537da16Jean-Michel Trivi                if (apc == null) {
498bd39cfaf97106bb8b9ea702d8e1cd5965537da16Jean-Michel Trivi                    continue;
499bd39cfaf97106bb8b9ea702d8e1cd5965537da16Jean-Michel Trivi                }
50062b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                final int playerUsage = apc.getAudioAttributes().getUsage();
50162b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                boolean mute = false;
50262b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                for (int usageToMute : usagesToMute) {
50362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    if (playerUsage == usageToMute) {
50462b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                        mute = true;
50562b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                        break;
50662b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    }
50762b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                }
50862b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                if (mute) {
50962b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    try {
51074a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                        sEventLogger.log((new AudioEventLogger.StringEvent("call: muting piid:"
51174a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                                + piid + " uid:" + apc.getClientUid())).printLog(TAG));
51262b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                        apc.getPlayerProxy().setVolume(0.0f);
513cafed63e3acfebe1c633433c9e3a6013bb1f47ccJean-Michel Trivi                        mMutedPlayers.add(new Integer(piid));
51462b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    } catch (Exception e) {
515952f2341abc398d245f3c0a577ebe1b28f93f368Jean-Michel Trivi                        Log.e(TAG, "call: error muting player " + piid, e);
51662b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    }
51762b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                }
51862b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            }
51962b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        }
52062b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    }
52162b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi
52262b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    @Override
52362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    public void unmutePlayersForCall() {
52462b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        if (DEBUG) {
52562b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            Log.v(TAG, "unmutePlayersForCall()");
52662b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        }
52762b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        synchronized (mPlayerLock) {
52862b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            if (mMutedPlayers.isEmpty()) {
52962b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                return;
53062b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            }
53162b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            for (int piid : mMutedPlayers) {
53262b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
53362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                if (apc != null) {
53462b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    try {
53574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                        sEventLogger.log(new AudioEventLogger.StringEvent("call: unmuting piid:"
53674a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                                + piid).printLog(TAG));
53762b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                        apc.getPlayerProxy().setVolume(1.0f);
53862b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    } catch (Exception e) {
539087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                        Log.e(TAG, "call: error unmuting player " + piid + " uid:"
540087b672797b23d6c7451f975ca7f825d64fb1bd9Jean-Michel Trivi                                + apc.getClientUid(), e);
54162b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                    }
54262b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi                }
54362b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi            }
544579c511765a23211a33a1b2f90010942ada2bccbJean-Michel Trivi            mMutedPlayers.clear();
54562b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi        }
54662b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi    }
54762b8634f06b32f17eced8020ecd9240f70838124Jean-Michel Trivi
548292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    //=================================================================
549292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    // Track playback activity listeners
550292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
551292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
552292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        if (pcdb == null) {
553292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            return;
554292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
555292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mClients) {
556292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
557292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            if (pmc.init()) {
558292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                if (!isPrivileged) {
559292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    mHasPublicClients = true;
560292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                }
561292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                mClients.add(pmc);
562292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
563292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
564292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
565292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
566292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
567292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        if (pcdb == null) {
568292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            return;
569292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
570292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mClients) {
571292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
572292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            boolean hasPublicClients = false;
573292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            // iterate over the clients to remove the dispatcher to remove, and reevaluate at
574292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            // the same time if we still have a public client.
575292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            while (clientIterator.hasNext()) {
576292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                PlayMonitorClient pmc = clientIterator.next();
577292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                if (pcdb.equals(pmc.mDispatcherCb)) {
578292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    pmc.release();
579292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    clientIterator.remove();
580292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                } else {
581292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    if (!pmc.mIsPrivileged) {
582292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                        hasPublicClients = true;
583292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                    }
584292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                }
585292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
586292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            mHasPublicClients = hasPublicClients;
587292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
588292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
589292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
59044a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi    List<AudioPlaybackConfiguration> getActivePlaybackConfigurations(boolean isPrivileged) {
591292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        synchronized(mPlayers) {
59244a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi            if (isPrivileged) {
59344a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                return new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
59444a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi            } else {
59544a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                final List<AudioPlaybackConfiguration> configsPublic;
59644a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                synchronized (mPlayerLock) {
59744a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                    configsPublic = anonymizeForPublicConsumption(
59844a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                            new ArrayList<AudioPlaybackConfiguration>(mPlayers.values()));
59944a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                }
60044a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi                return configsPublic;
60144a8f53f94808fdc5ac35a249d21ff2ba23e9419Jean-Michel Trivi            }
602292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
603292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
604292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
605292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
606292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    /**
607292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi     * Inner class to track clients that want to be notified of playback updates
608292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi     */
609c2769ab2ac908b4ea344cf22cfe8ff968a906649Jean-Michel Trivi    private static final class PlayMonitorClient implements IBinder.DeathRecipient {
610292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
611292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        // can afford to be static because only one PlaybackActivityMonitor ever instantiated
6129dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi        static PlaybackActivityMonitor sListenerDeathMonitor;
613292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
614292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        final IPlaybackConfigDispatcher mDispatcherCb;
615292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        final boolean mIsPrivileged;
616292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
617292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        int mErrorCount = 0;
618292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        // number of errors after which we don't update this client anymore to not spam the logs
619292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        static final int MAX_ERRORS = 5;
620292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
621292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
622292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            mDispatcherCb = pcdb;
623292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            mIsPrivileged = isPrivileged;
624292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
625292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
626292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        public void binderDied() {
627292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            Log.w(TAG, "client died");
6289dc22c227cb5c01136a6aa1b52c7dfa3383c0bd7Jean-Michel Trivi            sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb);
629292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
630292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
631292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        boolean init() {
632292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            try {
633292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                mDispatcherCb.asBinder().linkToDeath(this, 0);
634292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                return true;
635292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            } catch (RemoteException e) {
636292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                Log.w(TAG, "Could not link to client death", e);
637292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi                return false;
638292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            }
639292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
640292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi
641292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        void release() {
642292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi            mDispatcherCb.asBinder().unlinkToDeath(this, 0);
643292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi        }
644292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi    }
645cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
646cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi    //=================================================================
647cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi    // Class to handle ducking related operations for a given UID
648cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi    private static final class DuckingManager {
649cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
650cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
6512e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi        synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
6522e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            if (DEBUG) {  Log.v(TAG, "DuckingManager: duckUid() uid:"+ uid); }
653cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (!mDuckers.containsKey(uid)) {
654cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                mDuckers.put(uid, new DuckedApp(uid));
655cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
656cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            final DuckedApp da = mDuckers.get(uid);
657cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            for (AudioPlaybackConfiguration apc : apcsToDuck) {
6582e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                da.addDuck(apc, false /*skipRamp*/);
659cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
660cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        }
661cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
6622e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi        synchronized void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
6632e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            if (DEBUG) {  Log.v(TAG, "DuckingManager: unduckUid() uid:"+ uid); }
664cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            final DuckedApp da = mDuckers.remove(uid);
665cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (da == null) {
666cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                return;
667cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
668cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            da.removeUnduckAll(players);
669cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        }
670cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
671cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
6722e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi        synchronized void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
6732e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            if (DEBUG) {  Log.v(TAG, "DuckingManager: checkDuck() player piid:"
6742e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                    + apc.getPlayerInterfaceId()+ " uid:"+ apc.getClientUid()); }
675cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            final DuckedApp da = mDuckers.get(apc.getClientUid());
676cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (da == null) {
677cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                return;
678cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
6792e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            da.addDuck(apc, true /*skipRamp*/);
680cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        }
681cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
6822e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi        synchronized void dump(PrintWriter pw) {
683cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            for (DuckedApp da : mDuckers.values()) {
684cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                da.dump(pw);
685cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
686cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        }
687cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
6882e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi        synchronized void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
6892e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            final int uid = apc.getClientUid();
6902e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            if (DEBUG) {  Log.v(TAG, "DuckingManager: removedReleased() player piid: "
6912e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                    + apc.getPlayerInterfaceId() + " uid:" + uid); }
6922e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            final DuckedApp da = mDuckers.get(uid);
693cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            if (da == null) {
694cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                return;
695cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
696cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            da.removeReleased(apc);
697cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        }
698cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
699cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        private static final class DuckedApp {
700cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            private final int mUid;
701cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
702cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
703cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            DuckedApp(int uid) {
704cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                mUid = uid;
705cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
706cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
707cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            void dump(PrintWriter pw) {
708cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                pw.print("\t uid:" + mUid + " piids:");
709cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                for (int piid : mDuckedPlayers) {
710cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    pw.print(" " + piid);
711cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                }
712cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                pw.println("");
713cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
714cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
715cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            // pre-conditions:
716cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            //  * apc != null
717cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            //  * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
7182e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi            void addDuck(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
719cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                final int piid = new Integer(apc.getPlayerInterfaceId());
720cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                if (mDuckedPlayers.contains(piid)) {
7212e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                    if (DEBUG) { Log.v(TAG, "player piid:" + piid + " already ducked"); }
722cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    return;
723cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                }
724cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                try {
72574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                    sEventLogger.log((new DuckEvent(apc, skipRamp)).printLog(TAG));
726cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    apc.getPlayerProxy().applyVolumeShaper(
727cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                            DUCK_VSHAPE,
7282e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                            skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
729cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    mDuckedPlayers.add(piid);
730cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                } catch (Exception e) {
7312e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                    Log.e(TAG, "Error ducking player piid:" + piid + " uid:" + mUid, e);
732cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                }
733cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
734cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
735cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            void removeUnduckAll(HashMap<Integer, AudioPlaybackConfiguration> players) {
736cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                for (int piid : mDuckedPlayers) {
737cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    final AudioPlaybackConfiguration apc = players.get(piid);
738cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    if (apc != null) {
739cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                        try {
74074a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                            sEventLogger.log((new AudioEventLogger.StringEvent("unducking piid:"
74174a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                                    + piid)).printLog(TAG));
742cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                            apc.getPlayerProxy().applyVolumeShaper(
743cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                                    DUCK_ID,
744cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                                    VolumeShaper.Operation.REVERSE);
745cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                        } catch (Exception e) {
7462e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                            Log.e(TAG, "Error unducking player piid:" + piid + " uid:" + mUid, e);
747cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                        }
748cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    } else {
749cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                        // this piid was in the list of ducked players, but wasn't found
750cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                        if (DEBUG) {
7512e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                            Log.v(TAG, "Error unducking player piid:" + piid
7522e48fb55122ad11f7416a65b04034ef30c3a42f5Jean-Michel Trivi                                    + ", player not found for uid " + mUid);
753cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                        }
754cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                    }
755cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                }
756cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                mDuckedPlayers.clear();
757cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
758cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi
759cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
760cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi                mDuckedPlayers.remove(new Integer(apc.getPlayerInterfaceId()));
761cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi            }
762cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi        }
763cb84fc010998462b222fa5f784bcc54c9a829b36Jean-Michel Trivi    }
764011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
765011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    //=================================================================
766011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    // For logging
767011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    private final static class PlayerEvent extends AudioEventLogger.Event {
768011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        // only keeping the player interface ID as it uniquely identifies the player in the event
769011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        final int mPlayerIId;
770011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        final int mState;
771011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
772011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        PlayerEvent(int piid, int state) {
773011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mPlayerIId = piid;
774011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mState = state;
775011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        }
776011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
777011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        @Override
778011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        public String eventToString() {
7793120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi            return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
7803120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi                    .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
7813120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        }
7823120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi    }
7833120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi
7843120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi    private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event {
7853120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        // only keeping the player interface ID as it uniquely identifies the player in the event
7863120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        final int mPlayerIId;
7873120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        final boolean mHasOp;
7883120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        final int mUid;
7893120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi
7903120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        PlayerOpPlayAudioEvent(int piid, boolean hasOp, int uid) {
7913120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi            mPlayerIId = piid;
7923120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi            mHasOp = hasOp;
7933120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi            mUid = uid;
7943120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        }
7953120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi
7963120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        @Override
7973120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi        public String eventToString() {
7983120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi            return new StringBuilder("player piid:").append(mPlayerIId)
7993120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi                    .append(" has OP_PLAY_AUDIO:").append(mHasOp)
8003120059d5bdc52fb5ef2c90d9662562e92cd4df9Jean-Michel Trivi                    .append(" in uid:").append(mUid).toString();
801011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        }
802011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    }
803011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
804011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    private final static class NewPlayerEvent extends AudioEventLogger.Event {
805011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final int mPlayerIId;
806011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final int mPlayerType;
807011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final int mClientUid;
808011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final int mClientPid;
809011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final AudioAttributes mPlayerAttr;
810011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
811011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        NewPlayerEvent(AudioPlaybackConfiguration apc) {
812011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mPlayerIId = apc.getPlayerInterfaceId();
813011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mPlayerType = apc.getPlayerType();
814011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mClientUid = apc.getClientUid();
815011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mClientPid = apc.getClientPid();
816011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mPlayerAttr = apc.getAudioAttributes();
817011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        }
818011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
819011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        @Override
820011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        public String eventToString() {
821011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            return new String("new player piid:" + mPlayerIId + " uid/pid:" + mClientUid + "/"
822011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    + mClientPid + " type:"
823011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    + AudioPlaybackConfiguration.toLogFriendlyPlayerType(mPlayerType)
824011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi                    + " attr:" + mPlayerAttr);
825011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        }
826011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    }
827011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
82874a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi    private static final class DuckEvent extends AudioEventLogger.Event {
82974a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        private final int mPlayerIId;
83074a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        private final boolean mSkipRamp;
83174a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        private final int mClientUid;
83274a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        private final int mClientPid;
83374a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi
83474a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        DuckEvent(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
83574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            mPlayerIId = apc.getPlayerInterfaceId();
83674a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            mSkipRamp = skipRamp;
83774a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            mClientUid = apc.getClientUid();
83874a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            mClientPid = apc.getClientPid();
83974a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        }
84074a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi
84174a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        @Override
84274a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        public String eventToString() {
84374a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi            return new StringBuilder("ducking player piid:").append(mPlayerIId)
84474a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                    .append(" uid/pid:").append(mClientUid).append("/").append(mClientPid)
84574a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi                    .append(" skip ramp:").append(mSkipRamp).toString();
84674a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi        }
84774a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi    }
84874a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi
84974a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi    private static final class AudioAttrEvent extends AudioEventLogger.Event {
850011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final int mPlayerIId;
851011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        private final AudioAttributes mPlayerAttr;
852011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
853011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        AudioAttrEvent(int piid, AudioAttributes attr) {
854011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mPlayerIId = piid;
855011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            mPlayerAttr = attr;
856011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        }
857011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
858011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        @Override
859011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        public String eventToString() {
860011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            return new String("player piid:" + mPlayerIId + " new AudioAttributes:" + mPlayerAttr);
861011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi        }
862011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi    }
863011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi
86474a5596a8aeb4c112a6c024e9613d58ba662a5b5Jean-Michel Trivi    private static final AudioEventLogger sEventLogger = new AudioEventLogger(100,
865011f39e7c7a16424260310fb9f580c727b72e8d8Jean-Michel Trivi            "playback activity as reported through PlayerBase");
866292a6a4e9934a94eea97b018befde3baed895f7dJean-Michel Trivi}
867