AudioTrack: support ENCODING_IEC61937

Set DIRECT flag.
Use audio_has_proportional_frames() instead of audio_is_linear_pcm()
where appropriate.

Bug: 24541671
Bug: 20891646
Bug: 26373761
Change-Id: Ia32036b18683b084d6c9887593df87397ea0afd9
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e17e47e..b2a5f14 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -363,6 +363,8 @@
     // these below should probably come from the audioFlinger too...
     if (format == AUDIO_FORMAT_DEFAULT) {
         format = AUDIO_FORMAT_PCM_16_BIT;
+    } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
+        mAttributes.flags |= AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
     }
 
     // validate parameters
@@ -398,13 +400,13 @@
     }
 
     if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (audio_is_linear_pcm(format)) {
+        if (audio_has_proportional_frames(format)) {
             mFrameSize = channelCount * audio_bytes_per_sample(format);
         } else {
             mFrameSize = sizeof(uint8_t);
         }
     } else {
-        ALOG_ASSERT(audio_is_linear_pcm(format));
+        ALOG_ASSERT(audio_has_proportional_frames(format));
         mFrameSize = channelCount * audio_bytes_per_sample(format);
         // createTrack will return an error if PCM format is not supported by server,
         // so no need to check for specific PCM formats here
@@ -1221,7 +1223,7 @@
     mNotificationFramesAct = mNotificationFramesReq;
 
     size_t frameCount = mReqFrameCount;
-    if (!audio_is_linear_pcm(mFormat)) {
+    if (!audio_has_proportional_frames(mFormat)) {
 
         if (mSharedBuffer != 0) {
             // Same comment as below about ignoring frameCount parameter for set()
@@ -1944,7 +1946,7 @@
             return NS_NEVER;
         }
 
-        if (mRetryOnPartialBuffer && audio_is_linear_pcm(mFormat)) {
+        if (mRetryOnPartialBuffer && audio_has_proportional_frames(mFormat)) {
             mRetryOnPartialBuffer = false;
             if (avail < mRemainingFrames) {
                 if (ns > 0) { // account for obtain time
@@ -1990,7 +1992,7 @@
             // buffer size and skip the loop entirely.
 
             nsecs_t myns;
-            if (audio_is_linear_pcm(mFormat)) {
+            if (audio_has_proportional_frames(mFormat)) {
                 // time to wait based on buffer occupancy
                 const nsecs_t datans = mRemainingFrames <= avail ? 0 :
                         framesToNanoseconds(mRemainingFrames - avail, sampleRate, speed);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 6f34271..4ee8d6c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -107,7 +107,7 @@
 // ----------------------------------------------------------------------------
 
 const char *formatToString(audio_format_t format) {
-    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+    switch (audio_get_main_format(format)) {
     case AUDIO_FORMAT_PCM:
         switch (format) {
         case AUDIO_FORMAT_PCM_16_BIT: return "pcm16";
@@ -130,6 +130,7 @@
     case AUDIO_FORMAT_OPUS: return "opus";
     case AUDIO_FORMAT_AC3: return "ac-3";
     case AUDIO_FORMAT_E_AC3: return "e-ac-3";
+    case AUDIO_FORMAT_IEC61937: return "iec61937";
     default:
         break;
     }
@@ -1162,7 +1163,7 @@
         return 0;
     }
     if ((sampleRate == 0) ||
-            !audio_is_valid_format(format) || !audio_is_linear_pcm(format) ||
+            !audio_is_valid_format(format) || !audio_has_proportional_frames(format) ||
             !audio_is_input_channel(channelMask)) {
         return 0;
     }
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index 3191598..7494930 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -68,7 +68,7 @@
             status);
 
         // If the data is encoded then try again using wrapped PCM.
-        bool wrapperNeeded = !audio_is_linear_pcm(originalConfig.format)
+        bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
                 && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
                 && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
 
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index b6d1be7..6026bbb 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -35,7 +35,7 @@
         , mFramesWrittenAtStandby(0)
         , mRenderPosition(0)
         , mRateMultiplier(1)
-        , mHalFormatIsLinearPcm(false)
+        , mHalFormatHasProportionalFrames(false)
         , mHalFrameSize(0)
 {
 }
@@ -96,7 +96,7 @@
 
     // Adjust for standby using HAL rate frames.
     // Only apply this correction if the HAL is getting PCM frames.
-    if (mHalFormatIsLinearPcm) {
+    if (mHalFormatHasProportionalFrames) {
         uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
                 0 : (halPosition - mFramesWrittenAtStandby);
         // Scale from HAL sample rate to application rate.
@@ -116,16 +116,21 @@
         const char *address)
 {
     audio_stream_out_t *outStream;
+
+    audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
+                ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+                : flags;
+
     int status = hwDev()->open_output_stream(
             hwDev(),
             handle,
             devices,
-            flags,
+            customFlags,
             config,
             &outStream,
             address);
-    ALOGV("AudioStreamOut::open(), HAL open_output_stream returned "
-            " %p, sampleRate %d, Format %#x, "
+    ALOGV("AudioStreamOut::open(), HAL returned "
+            " stream %p, sampleRate %d, Format %#x, "
             "channelMask %#x, status %d",
             outStream,
             config->sample_rate,
@@ -133,10 +138,26 @@
             config->channel_mask,
             status);
 
+    // Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare
+    // it as PCM then it will probably work.
+    if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) {
+        struct audio_config customConfig = *config;
+        customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+
+        status = hwDev()->open_output_stream(
+                hwDev(),
+                handle,
+                devices,
+                customFlags,
+                &customConfig,
+                &outStream,
+                address);
+        ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status);
+    }
+
     if (status == NO_ERROR) {
         stream = outStream;
-        mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
-        ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
+        mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
         mHalFrameSize = audio_stream_out_frame_size(stream);
     }
 
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index 06a2277..768f537 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -106,7 +106,7 @@
     uint64_t             mFramesWrittenAtStandby;
     uint64_t             mRenderPosition; // reset by flush or standby
     int                  mRateMultiplier;
-    bool                 mHalFormatIsLinearPcm;
+    bool                 mHalFormatHasProportionalFrames;
     size_t               mHalFrameSize;
 };
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2fd5758..cfac81d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1815,7 +1815,7 @@
     // This is probably too conservative, but legacy application code may depend on it.
     // If you change this calculation, also review the start threshold which is related.
     if (!(*flags & IAudioFlinger::TRACK_FAST)
-            && audio_is_linear_pcm(format) && sharedBuffer == 0) {
+            && audio_has_proportional_frames(format) && sharedBuffer == 0) {
         // this must match AudioTrack.cpp calculateMinFrameCount().
         // TODO: Move to a common library
         uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
@@ -1838,7 +1838,7 @@
     switch (mType) {
 
     case DIRECT:
-        if (audio_is_linear_pcm(format)) {
+        if (audio_is_linear_pcm(format)) { // TODO maybe use audio_has_proportional_frames()?
             if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
                 ALOGE("createTrack_l() Bad parameter: sampleRate %u format %#x, channelMask 0x%08x "
                         "for output %p with format %#x",
@@ -4715,7 +4715,7 @@
         // Do not use a high threshold for compressed audio.
         uint32_t minFrames;
         if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()
-            && (track->mRetryCount > 1) && audio_is_linear_pcm(mFormat)) {
+            && (track->mRetryCount > 1) && audio_has_proportional_frames(mFormat)) {
             minFrames = mNormalFrameCount;
         } else {
             minFrames = 1;
@@ -4776,7 +4776,7 @@
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
                 size_t audioHALFrames;
-                if (audio_is_linear_pcm(mFormat)) {
+                if (audio_has_proportional_frames(mFormat)) {
                     audioHALFrames = (latency_l() * mSampleRate) / 1000;
                 } else {
                     audioHALFrames = 0;
@@ -4884,7 +4884,7 @@
         } else {
             mSleepTimeUs = mIdleSleepTimeUs;
         }
-    } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
+    } else if (mBytesWritten != 0 && audio_has_proportional_frames(mFormat)) {
         memset(mSinkBuffer, 0, mFrameCount * mFrameSize);
         mSleepTimeUs = 0;
     }
@@ -4991,7 +4991,7 @@
 uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const
 {
     uint32_t time;
-    if (audio_is_linear_pcm(mFormat)) {
+    if (audio_has_proportional_frames(mFormat)) {
         time = PlaybackThread::activeSleepTimeUs();
     } else {
         time = 10000;
@@ -5002,7 +5002,7 @@
 uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs() const
 {
     uint32_t time;
-    if (audio_is_linear_pcm(mFormat)) {
+    if (audio_has_proportional_frames(mFormat)) {
         time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
     } else {
         time = 10000;
@@ -5013,7 +5013,7 @@
 uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs() const
 {
     uint32_t time;
-    if (audio_is_linear_pcm(mFormat)) {
+    if (audio_has_proportional_frames(mFormat)) {
         time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000);
     } else {
         time = 10000;
@@ -5030,7 +5030,7 @@
     // no delay on outputs with HW A/V sync
     if (usesHwAvSync()) {
         mStandbyDelayNs = 0;
-    } else if ((mType == OFFLOAD) && !audio_is_linear_pcm(mFormat)) {
+    } else if ((mType == OFFLOAD) && !audio_has_proportional_frames(mFormat)) {
         mStandbyDelayNs = kOffloadStandbyDelayNs;
     } else {
         mStandbyDelayNs = microseconds(mActiveSleepTimeUs*2);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b4c1fdd..5e5920f 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -85,7 +85,7 @@
         mChannelCount(isOut ?
                 audio_channel_count_from_out_mask(channelMask) :
                 audio_channel_count_from_in_mask(channelMask)),
-        mFrameSize(audio_is_linear_pcm(format) ?
+        mFrameSize(audio_has_proportional_frames(format) ?
                 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
         mFrameCount(frameCount),
         mSessionId(sessionId),
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
index 58eaf79..f613f94 100644
--- a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -137,6 +137,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS),
     MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS_HD),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_IEC61937),
 };
 template<>
 const size_t FormatConverter::mSize = sizeof(FormatConverter::mTable) /
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ec70ed4..a5b1e47 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -711,7 +711,7 @@
     sp<SwAudioOutputDescriptor> desc;
     if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
         ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
-        if (!audio_is_linear_pcm(format)) {
+        if (!audio_has_proportional_frames(format)) {
             return BAD_VALUE;
         }
         *stream = streamTypefromAttributesInt(&attributes);