AAudio: Add AAudioStream_getHardware* functions

Add new methods to AAudioStream that allow for queries on the hardware
aspects of streams.

These will allow developers understand the hardware limitations of their
Android devices after they create AAudio streams.

Bug: 245412674
Test: atest AAudioTests
Change-Id: I104a738df89ab22aba9e0658b43402ddf053b887
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 9ca24aa..8528093 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -1694,22 +1694,55 @@
  * Available since API level 26.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return actual sample rate
+ * @return actual sample rate of the stream
  */
 AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * There may be sample rate conversions in the Audio framework.
+ * The sample rate set in the stream builder may not be actual sample rate used in the hardware.
+ *
+ * This returns the sample rate used by the hardware.
+ *
+ * If AAudioStreamBuilder_openStream() returned AAUDIO_OK, the result should always be valid.
+ *
+ * Available since API level 34.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual sample rate of the underlying hardware
+ */
+AAUDIO_API int32_t AAudioStream_getHardwareSampleRate(AAudioStream* stream)
+        __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
  * A stream has one or more channels of data.
  * A frame will contain one sample for each channel.
  *
  * Available since API level 26.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return actual number of channels
+ * @return actual number of channels of the stream
  */
 AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * There may be channel conversions in the Audio framework.
+ * The channel count or channel mask set in the stream builder may not be actual number of
+ * channels used in the hardware.
+ *
+ * This returns the channel count used by the hardware.
+ *
+ * If AAudioStreamBuilder_openStream() returned AAUDIO_OK, the result should always be valid.
+ *
+ * Available since API level 34.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual number of channels of the underlying hardware
+ */
+AAUDIO_API int32_t AAudioStream_getHardwareChannelCount(AAudioStream* stream)
+        __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
  * Identical to AAudioStream_getChannelCount().
  *
  * Available since API level 26.
@@ -1731,11 +1764,27 @@
  * Available since API level 26.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return actual data format
+ * @return actual data format of the stream
  */
 AAUDIO_API aaudio_format_t AAudioStream_getFormat(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * There may be data format conversions in the Audio framework.
+ * The data format set in the stream builder may not be actual format used in the hardware.
+ *
+ * This returns the audio format used by the hardware.
+ * AUDIO_FORMAT_PCM_8_24_BIT is currently not supported in AAudio, but the hardware may use it.
+ * If AUDIO_FORMAT_PCM_8_24_BIT is used by the hardware, return AAUDIO_FORMAT_PCM_I24_PACKED.
+ *
+ * Available since API level 34.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual data format of the underlying hardware.
+ */
+AAUDIO_API aaudio_format_t AAudioStream_getHardwareFormat(AAudioStream* stream)
+        __INTRODUCED_IN(__ANDROID_API_U__);
+
+/**
  * Provide actual sharing mode.
  *
  * Available since API level 26.
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index b60bac2..b1eefe4 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -40,6 +40,10 @@
     auto convFormat = android::aidl2legacy_AudioFormatDescription_audio_format_t(
             parcelable.audioFormat);
     setFormat(convFormat.ok() ? convFormat.value() : AUDIO_FORMAT_INVALID);
+    if (!convFormat.ok()) {
+        ALOGE("audioFormat (%s) aidl2legacy conversion failed",
+              parcelable.hardwareAudioFormat.toString().c_str());
+    }
     static_assert(sizeof(aaudio_direction_t) == sizeof(parcelable.direction));
     setDirection(parcelable.direction);
     static_assert(sizeof(audio_usage_t) == sizeof(parcelable.usage));
@@ -52,7 +56,6 @@
     setSpatializationBehavior(parcelable.spatializationBehavior);
     setIsContentSpatialized(parcelable.isContentSpatialized);
 
-
     static_assert(sizeof(aaudio_input_preset_t) == sizeof(parcelable.inputPreset));
     setInputPreset(parcelable.inputPreset);
     setBufferCapacity(parcelable.bufferCapacity);
@@ -62,6 +65,15 @@
     static_assert(sizeof(aaudio_session_id_t) == sizeof(parcelable.sessionId));
     setSessionId(parcelable.sessionId);
     setPrivacySensitive(parcelable.isPrivacySensitive);
+    setHardwareSamplesPerFrame(parcelable.hardwareSamplesPerFrame);
+    setHardwareSampleRate(parcelable.hardwareSampleRate);
+    auto convHardwareFormat = android::aidl2legacy_AudioFormatDescription_audio_format_t(
+            parcelable.hardwareAudioFormat);
+    setHardwareFormat(convHardwareFormat.ok() ? convHardwareFormat.value() : AUDIO_FORMAT_INVALID);
+    if (!convHardwareFormat.ok()) {
+        ALOGE("hardwareAudioFormat (%s) aidl2legacy conversion failed",
+              parcelable.hardwareAudioFormat.toString().c_str());
+    }
 }
 
 AAudioStreamConfiguration&
@@ -82,6 +94,8 @@
     if (convAudioFormat.ok()) {
         result.audioFormat = convAudioFormat.value();
     } else {
+        ALOGE("audioFormat (%s) legacy2aidl conversion failed",
+              audio_format_to_string(getFormat()));
         result.audioFormat = AudioFormatDescription{};
         result.audioFormat.type =
                 android::media::audio::common::AudioFormatType::SYS_RESERVED_INVALID;
@@ -100,5 +114,18 @@
     static_assert(sizeof(aaudio_session_id_t) == sizeof(result.sessionId));
     result.sessionId = getSessionId();
     result.isPrivacySensitive = isPrivacySensitive();
+    result.hardwareSamplesPerFrame = getHardwareSamplesPerFrame();
+    result.hardwareSampleRate = getHardwareSampleRate();
+    auto convHardwareAudioFormat = android::legacy2aidl_audio_format_t_AudioFormatDescription(
+            getHardwareFormat());
+    if (convHardwareAudioFormat.ok()) {
+        result.hardwareAudioFormat = convHardwareAudioFormat.value();
+    } else {
+        ALOGE("hardwareAudioFormat (%s) legacy2aidl conversion failed",
+              audio_format_to_string(getHardwareFormat()));
+        result.hardwareAudioFormat = AudioFormatDescription{};
+        result.hardwareAudioFormat.type =
+                android::media::audio::common::AudioFormatType::SYS_RESERVED_INVALID;
+    }
     return result;
 }
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
index 983e193..fa46e0d 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
@@ -34,4 +34,7 @@
     int /* aaudio_allowed_capture_policy_t */ allowedCapturePolicy;  // = AAUDIO_UNSPECIFIED;
     int /* aaudio_session_id_t */             sessionId;  //            = AAUDIO_SESSION_ID_NONE;
     boolean                                   isPrivacySensitive;  //   = false;
+    int                                       hardwareSamplesPerFrame;//= AAUDIO_UNSPECIFIED;
+    int                                       hardwareSampleRate;  //   = AAUDIO_UNSPECIFIED;
+    AudioFormatDescription                    hardwareAudioFormat;  //  = AUDIO_FORMAT_DEFAULT;
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2de878d..4956646 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -131,6 +131,10 @@
 
     request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
 
+    request.getConfiguration().setHardwareSamplesPerFrame(builder.getHardwareSamplesPerFrame());
+    request.getConfiguration().setHardwareSampleRate(builder.getHardwareSampleRate());
+    request.getConfiguration().setHardwareFormat(builder.getHardwareFormat());
+
     mDeviceChannelCount = getSamplesPerFrame(); // Assume it will be the same. Update if not.
 
     mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
@@ -192,6 +196,10 @@
     // Save device format so we can do format conversion and volume scaling together.
     setDeviceFormat(configurationOutput.getFormat());
 
+    setHardwareSamplesPerFrame(configurationOutput.getHardwareSamplesPerFrame());
+    setHardwareSampleRate(configurationOutput.getHardwareSampleRate());
+    setHardwareFormat(configurationOutput.getHardwareFormat());
+
     result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
     if (result != AAUDIO_OK) {
         goto error;
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 938079b..0c21e18 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -418,12 +418,24 @@
     return audioStream->getSampleRate();
 }
 
+AAUDIO_API int32_t AAudioStream_getHardwareSampleRate(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getHardwareSampleRate();
+}
+
 AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
     return audioStream->getSamplesPerFrame();
 }
 
+AAUDIO_API int32_t AAudioStream_getHardwareChannelCount(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getHardwareSamplesPerFrame();
+}
+
 AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream)
 {
     return AAudioStream_getChannelCount(stream);
@@ -443,6 +455,14 @@
     return AAudioConvert_androidToAAudioDataFormat(internalFormat);
 }
 
+AAUDIO_API aaudio_format_t AAudioStream_getHardwareFormat(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    // Use audio_format_t internally.
+    audio_format_t internalFormat = audioStream->getHardwareFormat();
+    return AAudioConvert_androidToNearestAAudioDataFormat(internalFormat);
+}
+
 AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* stream,
                                                 int32_t requestedFrames)
 {
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index e6b00d7..c8461cc 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -49,6 +49,9 @@
     mOpPackageName        = other.mOpPackageName;
     mAttributionTag       = other.mAttributionTag;
     mChannelMask          = other.mChannelMask;
+    mHardwareSamplesPerFrame = other.mHardwareSamplesPerFrame;
+    mHardwareSampleRate   = other.mHardwareSampleRate;
+    mHardwareAudioFormat  = other.mHardwareAudioFormat;
 }
 
 static aaudio_result_t isFormatValid(audio_format_t format) {
@@ -311,4 +314,7 @@
         "(null)" : mOpPackageName.value().c_str());
     ALOGD("mAttributionTag       = %s", !mAttributionTag.has_value() ?
         "(null)" : mAttributionTag.value().c_str());
-}
+    ALOGD("mHardwareSamplesPerFrame = %6d", mHardwareSamplesPerFrame);
+    ALOGD("mHardwareSampleRate   = %6d", mHardwareSampleRate);
+    ALOGD("mHardwareAudioFormat  = %6d", (int)mHardwareAudioFormat);
+}
\ No newline at end of file
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index cb998bf..565d54c 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -171,6 +171,30 @@
         mSamplesPerFrame = AAudioConvert_channelMaskToCount(channelMask);
     }
 
+    int32_t getHardwareSamplesPerFrame() const {
+        return mHardwareSamplesPerFrame;
+    }
+
+    void setHardwareSamplesPerFrame(int32_t hardwareSamplesPerFrame) {
+        mHardwareSamplesPerFrame = hardwareSamplesPerFrame;
+    }
+
+    int32_t getHardwareSampleRate() const {
+        return mHardwareSampleRate;
+    }
+
+    void setHardwareSampleRate(int32_t hardwareSampleRate) {
+        mHardwareSampleRate = hardwareSampleRate;
+    }
+
+    audio_format_t getHardwareFormat() const {
+        return mHardwareAudioFormat;
+    }
+
+    void setHardwareFormat(audio_format_t hardwareAudioFormat) {
+        mHardwareAudioFormat = hardwareAudioFormat;
+    }
+
     /**
      * @return bytes per frame of getFormat()
      */
@@ -210,6 +234,10 @@
     std::optional<std::string>      mOpPackageName        = {};
     std::optional<std::string>      mAttributionTag       = {};
     aaudio_channel_mask_t           mChannelMask          = AAUDIO_UNSPECIFIED;
+    int                             mHardwareSamplesPerFrame
+                                                          = AAUDIO_UNSPECIFIED;
+    int                             mHardwareSampleRate   = AAUDIO_UNSPECIFIED;
+    audio_format_t                  mHardwareAudioFormat  = AUDIO_FORMAT_DEFAULT;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index e36928d..75182dc 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -222,14 +222,26 @@
         return mSampleRate;
     }
 
+    aaudio_result_t getHardwareSampleRate() const {
+        return mHardwareSampleRate;
+    }
+
     audio_format_t getFormat()  const {
         return mFormat;
     }
 
+    audio_format_t getHardwareFormat()  const {
+        return mHardwareFormat;
+    }
+
     aaudio_result_t getSamplesPerFrame() const {
         return mSamplesPerFrame;
     }
 
+    aaudio_result_t getHardwareSamplesPerFrame() const {
+        return mHardwareSamplesPerFrame;
+    }
+
     virtual int32_t getPerformanceMode() const {
         return mPerformanceMode;
     }
@@ -528,6 +540,11 @@
     }
 
     // This should not be called after the open() call.
+    void setHardwareSampleRate(int32_t hardwareSampleRate) {
+        mHardwareSampleRate = hardwareSampleRate;
+    }
+
+    // This should not be called after the open() call.
     void setFramesPerBurst(int32_t framesPerBurst) {
         mFramesPerBurst = framesPerBurst;
     }
@@ -548,6 +565,16 @@
     }
 
     // This should not be called after the open() call.
+    void setHardwareFormat(audio_format_t format) {
+        mHardwareFormat = format;
+    }
+
+    // This should not be called after the open() call.
+    void setHardwareSamplesPerFrame(int32_t hardwareSamplesPerFrame) {
+        mHardwareSamplesPerFrame = hardwareSamplesPerFrame;
+    }
+
+    // This should not be called after the open() call.
     void setDeviceFormat(audio_format_t format) {
         mDeviceFormat = format;
     }
@@ -685,12 +712,15 @@
 
     // These do not change after open().
     int32_t                     mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t                     mHardwareSamplesPerFrame = AAUDIO_UNSPECIFIED;
     aaudio_channel_mask_t       mChannelMask = AAUDIO_UNSPECIFIED;
     int32_t                     mSampleRate = AAUDIO_UNSPECIFIED;
+    int32_t                     mHardwareSampleRate = AAUDIO_UNSPECIFIED;
     int32_t                     mDeviceId = AAUDIO_UNSPECIFIED;
     aaudio_sharing_mode_t       mSharingMode = AAUDIO_SHARING_MODE_SHARED;
     bool                        mSharingModeMatchRequired = false; // must match sharing mode requested
     audio_format_t              mFormat = AUDIO_FORMAT_DEFAULT;
+    audio_format_t              mHardwareFormat = AUDIO_FORMAT_DEFAULT;
     aaudio_performance_mode_t   mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
     int32_t                     mFramesPerBurst = 0;
     int32_t                     mBufferCapacity = 0;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 9a136a7..83cd45e 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -208,6 +208,10 @@
     setBufferCapacity(getBufferCapacityFromDevice());
     setFramesPerBurst(getFramesPerBurstFromDevice());
 
+    setHardwareSamplesPerFrame(mAudioRecord->getHalChannelCount());
+    setHardwareSampleRate(mAudioRecord->getHalSampleRate());
+    setHardwareFormat(mAudioRecord->getHalFormat());
+
     // We may need to pass the data through a block size adapter to guarantee constant size.
     if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
         // The block adapter runs before the format conversion.
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index fb3fcc1..e559d3c 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -202,6 +202,10 @@
     setBufferCapacity(getBufferCapacityFromDevice());
     setFramesPerBurst(getFramesPerBurstFromDevice());
 
+    setHardwareSamplesPerFrame(mAudioTrack->getHalChannelCount());
+    setHardwareSampleRate(mAudioTrack->getHalSampleRate());
+    setHardwareFormat(mAudioTrack->getHalFormat());
+
     // We may need to pass the data through a block size adapter to guarantee constant size.
     if (mCallbackBufferSize != AAUDIO_UNSPECIFIED) {
         // This may need to change if we add format conversion before
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index f45b816..e28dcb4 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -67,6 +67,9 @@
     AAudioStream_getChannelMask;  # introduced=32
     AAudioStream_getSpatializationBehavior;  # introduced=32
     AAudioStream_isContentSpatialized;       # introduced=32
+    AAudioStream_getHardwareChannelCount; # introduced=UpsideDownCake
+    AAudioStream_getHardwareFormat;       # introduced=UpsideDownCake
+    AAudioStream_getHardwareSampleRate;   # introduced=UpsideDownCake
   local:
     *;
 };
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index a197ced..69e51d6 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -180,6 +180,17 @@
     return aaudioFormat;
 }
 
+aaudio_format_t AAudioConvert_androidToNearestAAudioDataFormat(audio_format_t androidFormat) {
+    // Special case AUDIO_FORMAT_PCM_8_24_BIT because this function should be used to find the
+    // resolution of the data format. Setting AUDIO_FORMAT_PCM_8_24_BIT directly is not available
+    // from AAudio but hardware may use AUDIO_FORMAT_PCM_8_24_BIT under the hood.
+    if (androidFormat == AUDIO_FORMAT_PCM_8_24_BIT) {
+        ALOGD("%s() converting 8.24 to 24 bit packed", __func__);
+        return AAUDIO_FORMAT_PCM_I24_PACKED;
+    }
+    return AAudioConvert_androidToAAudioDataFormat(androidFormat);
+}
+
 // Make a message string from the condition.
 #define STATIC_ASSERT(condition) static_assert(condition, #condition)
 
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index b59ce1c..f3365eb 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -62,6 +62,7 @@
 
 aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t format);
 
+aaudio_format_t AAudioConvert_androidToNearestAAudioDataFormat(audio_format_t format);
 
 /**
  * Note that this function does not validate the passed in value.