Update audio ports with profile capabilities

When opening an output, import the profile capabilities associated
  with the device into the AudioPort.

Bug 10549017

Change-Id: If102f5623457542d2c1407ada303c71e43d19a08
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index f95b839..febc154 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -254,7 +254,7 @@
                 return NO_MEMORY;
             }
 
-            if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
+            if (checkOutputsForDevice(devDesc, state, outputs, address) != NO_ERROR) {
                 mAvailableOutputDevices.remove(devDesc);
                 return INVALID_OPERATION;
             }
@@ -275,7 +275,7 @@
             // remove device from available output devices
             mAvailableOutputDevices.remove(devDesc);
 
-            checkOutputsForDevice(device, state, outputs, address);
+            checkOutputsForDevice(devDesc, state, outputs, address);
             } break;
 
         default:
@@ -2947,7 +2947,7 @@
                         patchDesc->mPatch.sinks[j].ext.device.address;
                 if (strncmp(patchAddr,
                         address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
-                    ALOGV("checkOutputsForDevice(): adding opened output %d on same address %s",
+                    ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s",
                             desc->mIoHandle,  patchDesc->mPatch.sinks[j].ext.device.address);
                     outputs.add(desc->mIoHandle);
                     break;
@@ -2957,12 +2957,15 @@
     }
 }
 
-status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
+status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
                                                        audio_policy_dev_state_t state,
                                                        SortedVector<audio_io_handle_t>& outputs,
                                                        const String8 address)
 {
+    audio_devices_t device = devDesc->mDeviceType;
     sp<AudioOutputDescriptor> desc;
+    // erase all current sample rates, formats and channel masks
+    devDesc->clearCapabilities();
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
         // first list already open outputs that can be routed to this device
@@ -3011,6 +3014,9 @@
             for (j = 0; j < outputs.size(); j++) {
                 desc = mOutputs.valueFor(outputs.itemAt(j));
                 if (!desc->isDuplicated() && desc->mProfile == profile) {
+                    // matching profile: save the sample rates, format and channel masks supported
+                    // by the profile in our device descriptor
+                    devDesc->importAudioPort(profile);
                     break;
                 }
             }
@@ -3160,6 +3166,8 @@
                 profile_index--;
             } else {
                 outputs.add(output);
+                devDesc->importAudioPort(profile);
+
                 if (deviceDistinguishesOnAddress(device)) {
                     ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)",
                             device, address.string());
@@ -5539,15 +5547,21 @@
     port->type = mType;
     unsigned int i;
     for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
-        port->sample_rates[i] = mSamplingRates[i];
+        if (mSamplingRates[i] != 0) {
+            port->sample_rates[i] = mSamplingRates[i];
+        }
     }
     port->num_sample_rates = i;
     for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
-        port->channel_masks[i] = mChannelMasks[i];
+        if (mChannelMasks[i] != 0) {
+            port->channel_masks[i] = mChannelMasks[i];
+        }
     }
     port->num_channel_masks = i;
     for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
-        port->formats[i] = mFormats[i];
+        if (mFormats[i] != 0) {
+            port->formats[i] = mFormats[i];
+        }
     }
     port->num_formats = i;
 
@@ -5559,6 +5573,59 @@
     port->num_gains = i;
 }
 
+void AudioPolicyManager::AudioPort::importAudioPort(const sp<AudioPort> port) {
+    for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
+        const uint32_t rate = port->mSamplingRates.itemAt(k);
+        if (rate != 0) { // skip "dynamic" rates
+            bool hasRate = false;
+            for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
+                if (rate == mSamplingRates.itemAt(l)) {
+                    hasRate = true;
+                    break;
+                }
+            }
+            if (!hasRate) { // never import a sampling rate twice
+                mSamplingRates.add(rate);
+            }
+        }
+    }
+    for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
+        const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
+        if (mask != 0) { // skip "dynamic" masks
+            bool hasMask = false;
+            for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
+                if (mask == mChannelMasks.itemAt(l)) {
+                    hasMask = true;
+                    break;
+                }
+            }
+            if (!hasMask) { // never import a channel mask twice
+                mChannelMasks.add(mask);
+            }
+        }
+    }
+    for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
+        const audio_format_t format = port->mFormats.itemAt(k);
+        if (format != 0) { // skip "dynamic" formats
+            bool hasFormat = false;
+            for (size_t l = 0 ; l < mFormats.size() ; l++) {
+                if (format == mFormats.itemAt(l)) {
+                    hasFormat = true;
+                    break;
+                }
+            }
+            if (!hasFormat) { // never import a channel mask twice
+                mFormats.add(format);
+            }
+        }
+    }
+}
+
+void AudioPolicyManager::AudioPort::clearCapabilities() {
+    mChannelMasks.clear();
+    mFormats.clear();
+    mSamplingRates.clear();
+}
 
 void AudioPolicyManager::AudioPort::loadSamplingRates(char *name)
 {
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index 95aab65..f071675 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -238,6 +238,9 @@
 
             virtual void toAudioPort(struct audio_port *port) const;
 
+            void importAudioPort(const sp<AudioPort> port);
+            void clearCapabilities();
+
             void loadSamplingRates(char *name);
             void loadFormats(char *name);
             void loadOutChannels(char *name);
@@ -628,7 +631,7 @@
         // when a device is disconnected, checks if an output is not used any more and
         // returns its handle if any.
         // transfers the audio tracks and effects from one output thread to another accordingly.
-        status_t checkOutputsForDevice(audio_devices_t device,
+        status_t checkOutputsForDevice(const sp<DeviceDescriptor> devDesc,
                                        audio_policy_dev_state_t state,
                                        SortedVector<audio_io_handle_t>& outputs,
                                        const String8 address);