audio policy: fix AudioTrack output device selection

Have AudioTrack::setOutputDevice() set CBLK_INVALID flag instead
of calling restoreTrack_l(). This allows restoreTrack_l() to be called in
a safe context.

Allow device change while the AudioTrack is active by forcing a new
device selection in startOutput() if the output route for this
session was changed.

Remove some warnings.

Change-Id: I2d921a63c9bfa0e122233645e2d6d39f95f5f17d
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 055556f..7869a84 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1014,10 +1014,9 @@
     AutoMutex lock(mLock);
     if (mSelectedDeviceId != deviceId) {
         mSelectedDeviceId = deviceId;
-        return restoreTrack_l("setOutputDevice() restart");
-    } else {
-        return NO_ERROR;
+        android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
     }
+    return NO_ERROR;
 }
 
 audio_port_handle_t AudioTrack::getOutputDevice() {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 9573583..0715eea 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -52,6 +52,9 @@
     // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE)
     // - have the same address or one device does not specify the address
     // - have the same channel mask or one device does not specify the channel mask
+    if (other == 0) {
+        return false;
+    }
     return (mDeviceType == other->mDeviceType) &&
            (mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
            (mChannelMask == 0 || other->mChannelMask == 0 ||
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 3ea6a11..01f2b61 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -969,6 +969,8 @@
     audio_devices_t newDevice;
     if (outputDesc->mPolicyMix != NULL) {
         newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    } else if (mOutputRoutes.hasRouteChanged(session)) {
+        newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
     } else {
         newDevice = AUDIO_DEVICE_NONE;
     }
@@ -1026,7 +1028,7 @@
     // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
     outputDesc->changeRefCount(stream, 1);
 
-    if (outputDesc->mRefCount[stream] == 1) {
+    if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) {
         // starting an output being rerouted?
         if (device == AUDIO_DEVICE_NONE) {
             device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -2462,14 +2464,14 @@
     return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
 }
 
-status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
-                                       const audio_attributes_t *attributes,
-                                       audio_io_handle_t *handle)
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused,
+                                       const audio_attributes_t *attributes __unused,
+                                       audio_io_handle_t *handle __unused)
 {
     return INVALID_OPERATION;
 }
 
-status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle)
+status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
 {
     return INVALID_OPERATION;
 }
@@ -4511,18 +4513,36 @@
     return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
 }
 
+bool AudioPolicyManager::SessionRouteMap::hasRouteChanged(audio_session_t session)
+{
+    if (indexOfKey(session) >= 0) {
+        if (valueFor(session)->mChanged) {
+            valueFor(session)->mChanged = false;
+            return true;
+        }
+    }
+    return false;
+}
+
 void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session,
                                                    audio_stream_type_t streamType,
                                                    sp<DeviceDescriptor> deviceDescriptor)
 {
     sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
     if (route != NULL) {
+        if ((route->mDeviceDescriptor == 0 && deviceDescriptor != 0) ||
+                (!route->mDeviceDescriptor->equals(deviceDescriptor))) {
+            route->mChanged = true;
+        }
         route->mRefCount++;
         route->mDeviceDescriptor = deviceDescriptor;
     } else {
         route = new AudioPolicyManager::SessionRoute(session, streamType, deviceDescriptor);
         route->mRefCount++;
         add(session, route);
+        if (deviceDescriptor != 0) {
+            route->mChanged = true;
+        }
     }
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 146a7af..521f6c4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -244,7 +244,10 @@
                   mStreamType(streamType),
                   mDeviceDescriptor(deviceDescriptor),
                   mRefCount(0),
-                  mActivityCount(0) {}
+                  mActivityCount(0),
+                  mChanged(false) {}
+
+            void log(const char* prefix);
 
             audio_session_t         mSession;
             audio_stream_type_t     mStreamType;
@@ -252,10 +255,9 @@
             sp<DeviceDescriptor>    mDeviceDescriptor;
 
             // "reference" counting
-            int mRefCount;       // +/- on references
-            int mActivityCount;  // +/- on start/stop
-
-            void log(const char* prefix);
+            int                     mRefCount;      // +/- on references
+            int                     mActivityCount; // +/- on start/stop
+            bool                    mChanged;
         };
 
         class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>>
@@ -268,7 +270,7 @@
 
             int incRouteActivity(audio_session_t session);
             int decRouteActivity(audio_session_t session);
-
+            bool hasRouteChanged(audio_session_t session); // also clears the changed flag
             void log(const char* caption);
         };
 
@@ -510,6 +512,8 @@
 
         void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0);
 
+        // if argument "device" is different from AUDIO_DEVICE_NONE,  startSource() will force
+        // the re-evaluation of the output device.
         status_t startSource(sp<AudioOutputDescriptor> outputDesc,
                              audio_stream_type_t stream,
                              audio_devices_t device,