AudioPolicyManager: return output for audio attributes

In AudioPolicyManager, support querying an output
 or playback strategy for audio attributes,
 instead of a stream type,
In AudioTrack creation, use the output returned
 for the track's attributes.

Change-Id: I0fef05845ba676404775e2e338c10e6a96237268
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index a4722cb..c89ceaa 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -99,6 +99,8 @@
     // to be non-zero if status == NO_ERROR
     static status_t getOutputSamplingRate(uint32_t* samplingRate,
             audio_stream_type_t stream);
+    static status_t getOutputSamplingRateForAttr(uint32_t* samplingRate,
+                const audio_attributes_t *attr);
     static status_t getOutputFrameCount(size_t* frameCount,
             audio_stream_type_t stream);
     static status_t getOutputLatency(uint32_t* latency,
@@ -212,7 +214,12 @@
                                         audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
                                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                         const audio_offload_info_t *offloadInfo = NULL);
-
+    static audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                        uint32_t samplingRate = 0,
+                                        audio_format_t format = AUDIO_FORMAT_DEFAULT,
+                                        audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
+                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                        const audio_offload_info_t *offloadInfo = NULL);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
                                 int session);
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index d422aa3..959e4c3 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -56,6 +56,12 @@
                                         audio_channel_mask_t channelMask = 0,
                                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                         const audio_offload_info_t *offloadInfo = NULL) = 0;
+    virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                            uint32_t samplingRate = 0,
+                                            audio_format_t format = AUDIO_FORMAT_DEFAULT,
+                                            audio_channel_mask_t channelMask = 0,
+                                            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                            const audio_offload_info_t *offloadInfo = NULL) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session = 0) = 0;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 15b32ff..f5e7a78 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -245,6 +245,19 @@
     return getSamplingRate(output, samplingRate);
 }
 
+status_t AudioSystem::getOutputSamplingRateForAttr(uint32_t* samplingRate,
+        const audio_attributes_t *attr)
+{
+    if (attr == NULL) {
+        return BAD_VALUE;
+    }
+    audio_io_handle_t output = getOutputForAttr(attr);
+    if (output == 0) {
+        return PERMISSION_DENIED;
+    }
+    return getSamplingRate(output, samplingRate);
+}
+
 status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
                                       uint32_t* samplingRate)
 {
@@ -633,6 +646,19 @@
     return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
 }
 
+audio_io_handle_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo)
+{
+    if (attr == NULL) return 0;
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return 0;
+    return aps->getOutputForAttr(attr, samplingRate, format, channelMask, flags, offloadInfo);
+}
+
 status_t AudioSystem::startOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   int session)
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 000185b..77419f0 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -287,8 +287,7 @@
 
     status_t status;
     if (sampleRate == 0) {
-        // TODO replace with new APM method with support for audio_attributes_t
-        status = AudioSystem::getOutputSamplingRate(&sampleRate, mStreamType);
+        status = AudioSystem::getOutputSamplingRateForAttr(&sampleRate, &mAttributes);
         if (status != NO_ERROR) {
             ALOGE("Could not get output sample rate for stream type %d; status %d",
                     mStreamType, status);
@@ -641,8 +640,7 @@
     }
 
     uint32_t afSamplingRate;
-    // TODO replace with new APM method with support for audio_attributes_t
-    if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
+    if (AudioSystem::getOutputSamplingRateForAttr(&afSamplingRate, &mAttributes) != NO_ERROR) {
         return NO_INIT;
     }
     // Resampler implementation limits input sampling rate to 2 x output sampling rate.
@@ -889,13 +887,12 @@
         return NO_INIT;
     }
 
-    // TODO replace with new APM method with support for audio_attributes_t
-    audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat,
+    audio_io_handle_t output = AudioSystem::getOutputForAttr(&mAttributes, mSampleRate, mFormat,
             mChannelMask, mFlags, mOffloadInfo);
     if (output == AUDIO_IO_HANDLE_NONE) {
-        ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, "
-              "channel mask %#x, flags %#x",
-              mStreamType, mSampleRate, mFormat, mChannelMask, mFlags);
+        ALOGE("Could not get audio output for stream type %d, usage %d, sample rate %u, format %#x,"
+              " channel mask %#x, flags %#x",
+              mStreamType, mAttributes.usage, mSampleRate, mFormat, mChannelMask, mFlags);
         return BAD_VALUE;
     }
     {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 77d131b..41a9065 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -64,7 +64,8 @@
     RELEASE_AUDIO_PATCH,
     LIST_AUDIO_PATCHES,
     SET_AUDIO_PORT_CONFIG,
-    REGISTER_CLIENT
+    REGISTER_CLIENT,
+    GET_OUTPUT_FOR_ATTR
 };
 
 class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -155,6 +156,36 @@
         return static_cast <audio_io_handle_t> (reply.readInt32());
     }
 
+    virtual audio_io_handle_t getOutputForAttr(
+                                            const audio_attributes_t *attr,
+                                            uint32_t samplingRate,
+                                            audio_format_t format,
+                                            audio_channel_mask_t channelMask,
+                                            audio_output_flags_t flags,
+                                            const audio_offload_info_t *offloadInfo)
+        {
+            Parcel data, reply;
+            data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+            if (attr == NULL) {
+                ALOGE("Writing NULL audio attributes - shouldn't happen");
+                return (audio_io_handle_t) 0;
+            }
+            data.write(attr, sizeof(audio_attributes_t));
+            data.writeInt32(samplingRate);
+            data.writeInt32(static_cast <uint32_t>(format));
+            data.writeInt32(channelMask);
+            data.writeInt32(static_cast <uint32_t>(flags));
+            // hasOffloadInfo
+            if (offloadInfo == NULL) {
+                data.writeInt32(0);
+            } else {
+                data.writeInt32(1);
+                data.write(offloadInfo, sizeof(audio_offload_info_t));
+            }
+            remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply);
+            return static_cast <audio_io_handle_t> (reply.readInt32());
+        }
+
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session)
@@ -614,6 +645,30 @@
             return NO_ERROR;
         } break;
 
+        case GET_OUTPUT_FOR_ATTR: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            audio_attributes_t *attr = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+            data.read(attr, sizeof(audio_attributes_t));
+            uint32_t samplingRate = data.readInt32();
+            audio_format_t format = (audio_format_t) data.readInt32();
+            audio_channel_mask_t channelMask = data.readInt32();
+            audio_output_flags_t flags =
+                    static_cast <audio_output_flags_t>(data.readInt32());
+            bool hasOffloadInfo = data.readInt32() != 0;
+            audio_offload_info_t offloadInfo;
+            if (hasOffloadInfo) {
+                data.read(&offloadInfo, sizeof(audio_offload_info_t));
+            }
+            audio_io_handle_t output = getOutputForAttr(attr,
+                    samplingRate,
+                    format,
+                    channelMask,
+                    flags,
+                    hasOffloadInfo ? &offloadInfo : NULL);
+            reply->writeInt32(static_cast <int>(output));
+            return NO_ERROR;
+        } break;
+
         case START_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c025a45..33e4397 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -90,6 +90,12 @@
                                         audio_channel_mask_t channelMask,
                                         audio_output_flags_t flags,
                                         const audio_offload_info_t *offloadInfo) = 0;
+    virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                                uint32_t samplingRate,
+                                                audio_format_t format,
+                                                audio_channel_mask_t channelMask,
+                                                audio_output_flags_t flags,
+                                                const audio_offload_info_t *offloadInfo) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding stream.
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index 8cc386a..6342d8f 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -131,6 +131,22 @@
                                     format, channelMask, flags, offloadInfo);
 }
 
+audio_io_handle_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo)
+{
+    if (mAudioPolicyManager == NULL) {
+        return 0;
+    }
+    ALOGV("getOutput()");
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->getOutputForAttr(attr, samplingRate,
+                                    format, channelMask, flags, offloadInfo);
+}
+
 status_t AudioPolicyService::startOutput(audio_io_handle_t output,
                                          audio_stream_type_t stream,
                                          int session)
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index d4c9374..70dcb4c 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -623,13 +623,53 @@
                                     audio_output_flags_t flags,
                                     const audio_offload_info_t *offloadInfo)
 {
-    audio_io_handle_t output = 0;
-    uint32_t latency = 0;
+
     routing_strategy strategy = getStrategy(stream);
     audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
     ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
           device, stream, samplingRate, format, channelMask, flags);
 
+    return getOutputForDevice(device, stream, samplingRate,format, channelMask, flags,
+            offloadInfo);
+}
+
+audio_io_handle_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo)
+{
+    if (attr == NULL) {
+        ALOGE("getOutputForAttr() called with NULL audio attributes");
+        return 0;
+    }
+    ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s",
+            attr->usage, attr->content_type, attr->tags);
+
+    // TODO this is where filtering for custom policies (rerouting, dynamic sources) will go
+    routing_strategy strategy = (routing_strategy) getStrategyForAttr(attr);
+    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    ALOGV("getOutputForAttr() device %d, samplingRate %d, format %x, channelMask %x, flags %x",
+          device, samplingRate, format, channelMask, flags);
+
+    audio_stream_type_t stream = streamTypefromAttributesInt(attr);
+    return getOutputForDevice(device, stream, samplingRate, format, channelMask, flags,
+                offloadInfo);
+}
+
+audio_io_handle_t AudioPolicyManager::getOutputForDevice(
+        audio_devices_t device,
+        audio_stream_type_t stream,
+        uint32_t samplingRate,
+        audio_format_t format,
+        audio_channel_mask_t channelMask,
+        audio_output_flags_t flags,
+        const audio_offload_info_t *offloadInfo)
+{
+    audio_io_handle_t output = 0;
+    uint32_t latency = 0;
+
 #ifdef AUDIO_POLICY_TEST
     if (mCurOutput != 0) {
         ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d",
@@ -3239,6 +3279,44 @@
     }
 }
 
+uint32_t AudioPolicyManager::getStrategyForAttr(const audio_attributes_t *attr) {
+    // flags to strategy mapping
+    if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
+        return (uint32_t) STRATEGY_ENFORCED_AUDIBLE;
+    }
+
+    // usage to strategy mapping
+    switch (attr->usage) {
+    case AUDIO_USAGE_MEDIA:
+    case AUDIO_USAGE_GAME:
+    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+    case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+    case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+        return (uint32_t) STRATEGY_MEDIA;
+
+    case AUDIO_USAGE_VOICE_COMMUNICATION:
+        return (uint32_t) STRATEGY_PHONE;
+
+    case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+        return (uint32_t) STRATEGY_DTMF;
+
+    case AUDIO_USAGE_ALARM:
+    case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+        return (uint32_t) STRATEGY_SONIFICATION;
+
+    case AUDIO_USAGE_NOTIFICATION:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+    case AUDIO_USAGE_NOTIFICATION_EVENT:
+        return (uint32_t) STRATEGY_SONIFICATION_RESPECTFUL;
+
+    case AUDIO_USAGE_UNKNOWN:
+    default:
+        return (uint32_t) STRATEGY_MEDIA;
+    }
+}
+
 void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
     switch(stream) {
     case AUDIO_STREAM_MUSIC:
@@ -5916,4 +5994,46 @@
     mHwModules.add(module);
 }
 
+audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr)
+{
+    // flags to stream type mapping
+    if ((attr->flags & AUDIO_FLAG_AUDIBILITY_ENFORCED) == AUDIO_FLAG_AUDIBILITY_ENFORCED) {
+        return AUDIO_STREAM_ENFORCED_AUDIBLE;
+    }
+    if ((attr->flags & AUDIO_FLAG_SCO) == AUDIO_FLAG_SCO) {
+        return AUDIO_STREAM_BLUETOOTH_SCO;
+    }
+
+    // usage to stream type mapping
+    switch (attr->usage) {
+    case AUDIO_USAGE_MEDIA:
+    case AUDIO_USAGE_GAME:
+    case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+    case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+        return AUDIO_STREAM_MUSIC;
+    case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+        return AUDIO_STREAM_SYSTEM;
+    case AUDIO_USAGE_VOICE_COMMUNICATION:
+        return AUDIO_STREAM_VOICE_CALL;
+
+    case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+        return AUDIO_STREAM_DTMF;
+
+    case AUDIO_USAGE_ALARM:
+        return AUDIO_STREAM_ALARM;
+    case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+        return AUDIO_STREAM_RING;
+
+    case AUDIO_USAGE_NOTIFICATION:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+    case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+    case AUDIO_USAGE_NOTIFICATION_EVENT:
+        return AUDIO_STREAM_NOTIFICATION;
+
+    case AUDIO_USAGE_UNKNOWN:
+    default:
+        return AUDIO_STREAM_MUSIC;
+    }
+}
 }; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index 1abeb6a..c23d994 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -84,6 +84,12 @@
                                             audio_channel_mask_t channelMask,
                                             audio_output_flags_t flags,
                                             const audio_offload_info_t *offloadInfo);
+        virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                            uint32_t samplingRate,
+                                            audio_format_t format,
+                                            audio_channel_mask_t channelMask,
+                                            audio_output_flags_t flags,
+                                            const audio_offload_info_t *offloadInfo);
         virtual status_t startOutput(audio_io_handle_t output,
                                      audio_stream_type_t stream,
                                      int session = 0);
@@ -116,6 +122,8 @@
 
         // return the strategy corresponding to a given stream type
         virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
+        // return the strategy corresponding to the given audio attributes
+        virtual uint32_t getStrategyForAttr(const audio_attributes_t *attr);
 
         // return the enabled output devices for the given stream type
         virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
@@ -755,6 +763,17 @@
         uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }
         // converts device address to string sent to audio HAL via setParameters
         static String8 addressToParameter(audio_devices_t device, const String8 address);
+        // internal method to return the output handle for the given device and format
+        audio_io_handle_t getOutputForDevice(
+                audio_devices_t device,
+                audio_stream_type_t stream,
+                uint32_t samplingRate,
+                audio_format_t format,
+                audio_channel_mask_t channelMask,
+                audio_output_flags_t flags,
+                const audio_offload_info_t *offloadInfo);
+        // internal function to derive a stream type value from audio attributes
+        audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
 };
 
 };
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 66d9cad..69673cd 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -70,6 +70,12 @@
                                         audio_output_flags_t flags =
                                                 AUDIO_OUTPUT_FLAG_NONE,
                                         const audio_offload_info_t *offloadInfo = NULL);
+    virtual audio_io_handle_t getOutputForAttr(const audio_attributes_t *attr,
+                                            uint32_t samplingRate = 0,
+                                            audio_format_t format = AUDIO_FORMAT_DEFAULT,
+                                            audio_channel_mask_t channelMask = 0,
+                                            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                            const audio_offload_info_t *offloadInfo = NULL);
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session = 0);