Contribution of LDAC Adaptive Bit Rate am: 878aad2a83 am: b4f70c5b72
am: 147d610ad3

Change-Id: I32c749ca444e894c6d62e1e61d55463c00f504cd
diff --git a/Android.bp b/Android.bp
index 86d3b14..e159c7f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,3 +14,16 @@
     // unit such as ARM Cortex-R series or external 32-bit DSPs.
     cflags: ["-O2", "-Werror", "-Wall", "-Wextra"],
 }
+
+cc_library_shared {
+    name: "libldacBT_abr",
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+    export_include_dirs: ["abr/inc"],
+    srcs: ["abr/src/ldacBT_abr.c"],
+    shared_libs: ["libldacBT_enc"],
+    cflags: ["-O2", "-Werror", "-Wall", "-Wextra"]
+}
diff --git a/abr/inc/ldacBT_abr.h b/abr/inc/ldacBT_abr.h
new file mode 100644
index 0000000..135238f
--- /dev/null
+++ b/abr/inc/ldacBT_abr.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 - 2017 Sony Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LDACBT_ABR_H_
+#define _LDACBT_ABR_H_
+
+/* This file contains the definitions, declarations and macros for an implementation of
+ * LDAC Adaptive Bit Rate (hereinafter ABR) processing.
+ *
+ * The basic flow of the ABR processing is as follows:
+ * - The program creates a handle of LDAC ABR API using ldac_ABR_get_handle().
+ * - The program initializes the handle by setting the ldac_ABR_Proc() call interval to
+ *   ldac_ABR_Init().
+ *       The interval shall be as short as possible at the timing without accumulation
+ *       of packet in the buffer if propagation environment is fine.
+ * - The program reinitializes the handle by calling ldac_ABR_Init() again when the
+ *   state of the TX queue changes greatly, such as clearing the queue.
+ * - If the program demands to control the thresholds, then ldac_ABR_set_thresholds()
+ *   should be called.
+ * - The program sets flagEnable to "1" when allowing LDAC encode bitrate to be
+ *   adjusted by ABR, and sets it to "0" if it is not allowed.
+ * - The program calls ldac_ABR_Proc() at the interval set to ldac_ABR_Init() even if
+ *   flagEnable is "0".
+ *       The program passes TxQueueDepth and flagEnable to ldac_ABR_Proc() at this call,
+ *       LDAC encode bitrate is adjusted only when flagEnable is "1".
+ *       Otherwise, the internal parameters are updated and analyzed then returned.
+ *       The ABR handle adjusts eqmid based on TxQueueDepth which is passed from the program.
+ *       The ABR handle calls LDAC encode API ldacBT_alter_eqmid_priority() to adjust eqmid.
+ *       The ABR handle calls LDAC encode API ldacBT_get_eqmid() to get current eqmid.
+ * - The handle may be released with ldac_ABR_free_handle().
+ *
+ * Notes on debugging LDAC ABR:
+ * The meaning of "works fine" is that the bit rate will be low in case of bad radio situation
+ * and high in case of good radio situation.
+ *
+ * The bit rate transition can be debug by checking logcat messages from LDAC ABR library which
+ * built with the following changes in Android.bp:
+ *  - Adding "liblog" to shared_libs.
+ *  - Adding "-DLOCAL_DEBUG" to cflags.
+ * The messages are formated as follows:
+ *       [LDAC ABR] - abrQualityModeID : 0 -- eqmid : 0 -- TxQue : 0
+ *     where abrQualityModeID and eqmid related to the current bit rate and TxQue shows the depth
+ *     of current Tx queue.
+ *     The relationship between abrQualityModeID, eqmid and the bit rate is described in
+ *     "ldacBT_abr.c".
+ *
+ * The bit rate transition can be estimated/debug by listening to the audio played on the SNK
+ * device. This method cannot use to confirm the details of the bit rate transition, but useful
+ * to know how LDAC ABR algorithm works in a field test without checking the log.
+ * To try this method, rebuilding of the "libldacBT_enc" library with the following change in
+ * Android.bp is required:
+ *  - Adding "-DUSE_LDAC_ENC_SETTING_FOR_ABR_DEBUG" to cflags.
+ * By defining the above macro, the lower the bit rate, the greatly lower the bandwidth of the audio
+ * played on the SNK device. Therefore, the audio played on the SNK device will sounds like a
+ * low-pass filtered sound when the bit rate is low and will sounds as usual when the bit rate is
+ * enough high. It is recommend using sound such as white noise to hear those changes for the first
+ * time.
+ *
+ * IMPORTANT:
+ * These libraries modified as described above shall be used only to confirm the bit rate transition
+ * and SHALL NOT BE USED FOR FINAL PRODUCTS.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef LDAC_ABR_API
+#define LDAC_ABR_API
+#endif /* LDAC_ABR_API */
+
+#include <ldacBT.h> /* HANDLE_LDAC_BT */
+
+/* LDAC ABR handle type*/
+typedef struct _ldacbt_abr_param * HANDLE_LDAC_ABR;
+
+/* Allocation of LDAC ABR handle.
+ *  Format
+ *      HANDLE_LDAC_ABR  ldacBT_get_handle( void );
+ *  Arguments
+ *      None.
+ *  Return value
+ *      HANDLE_LDAC_ABR for success, NULL for failure.
+ */
+LDAC_ABR_API HANDLE_LDAC_ABR ldac_ABR_get_handle(void);
+
+/* Release of LDAC ABR handle.
+ *  Format
+ *      void  ldac_ABR_free_handle( HANDLE_LDAC_ABR );
+ *  Arguments
+ *      hLdacAbr    HANDLE_LDAC_ABR    LDAC ABR handle.
+ *  Return value
+ *      None.
+ */
+LDAC_ABR_API void ldac_ABR_free_handle(HANDLE_LDAC_ABR hLdacAbr);
+
+/* Initialize LDAC ABR.
+ *  Format
+ *      int  ldac_ABR_Init( HANDLE_LDAC_ABR, unsigned int );
+ *  Arguments
+ *      hLdacAbr        HANDLE_LDAC_ABR    LDAC ABR handle.
+ *      interval_ms     unsigned int       interval in ms for calling ldac_ABR_Proc().
+ *                                         interval of 1ms to 500ms is valid.
+ *  Return value
+ *      int: 0 for success, -1 for failure.
+ */
+LDAC_ABR_API int ldac_ABR_Init(HANDLE_LDAC_ABR hLdacAbr, unsigned int interval_ms);
+
+/* Setup thresholds for LDAC ABR.
+ *  Format
+ *      int ldac_ABR_set_thresholds( HANDLE_LDAC_ABR, unsigned int, unsigned int, unsigned int );
+ *  Arguments
+ *      hLdacAbr            HANDLE_LDAC_ABR  LDAC ABR handle.
+ *      thCritical          unsigned int     threshold for critical TxQueueDepth status.
+ *      thDangerousTrend    unsigned int     threshold for dangerous trend of TxQueueDepth.
+ *      thSafety4HQSQ       unsigned int     safety threshold for LDACBT_EQMID_HQ and
+ *                                           LDACBT_EQMID_SQ.
+ *  Return value
+ *      int: 0 for success, -1 for failure.
+ *  Remarks
+ *    Those thresholds should be the number of packets stored in the TX queue and should be
+ *    greater than 0.
+ *    The thCritical and thDangerousTrend are used for all eqmid and thSafety4HQSQ is used
+ *    only for LDACBT_EQMID_HQ and LDACBT_EQMID_SQ. Therefore, those thresholds must satisfy
+ *    the following releationship:
+ *        thCritical >= thDangerousTrend >= thSafety4HQSQ
+ */
+LDAC_ABR_API int ldac_ABR_set_thresholds(HANDLE_LDAC_ABR hLdacAbr, unsigned int thCritical,
+                                    unsigned int thDangerousTrend, unsigned int thSafety4HQSQ);
+
+/* LDAC ABR main process.
+ *  Format
+ *      int  ldac_ABR_Proc( HANDLE_LDAC_BT, HANDLE_LDAC_ABR, unsigned int, unsigned int );
+ *  Arguments
+ *      hLdacBt        HANDLE_LDAC_BT    LDAC handle.
+ *      hLdacAbr       HANDLE_LDAC_ABR   LDAC ABR handle.
+ *      TxQueueDepth   unsigned int      depth of TX queue.
+ *      flagEnable     unsigned int      flag indicating whether ABR is allowed to adjust LDAC
+ *                                       encode bitrate
+ *  Return value
+ *      int: updated Encode Quality Mode Index for success, -1 for failure.
+ */
+LDAC_ABR_API int ldac_ABR_Proc(HANDLE_LDAC_BT hLdacBt, HANDLE_LDAC_ABR hLdacAbr,
+                                 unsigned int TxQueueDepth, unsigned int flagEnable);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDACBT_ABR_H_ */
+
diff --git a/abr/src/ldacBT_abr.c b/abr/src/ldacBT_abr.c
new file mode 100644
index 0000000..b9bf4be
--- /dev/null
+++ b/abr/src/ldacBT_abr.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2014 - 2017 Sony Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ldacBT_abr.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LDAC_ABR_OBSERVING_TIME_MS 500 /* [ms] the time length for storing Tx Queue Depth */
+#define LDAC_ABR_PENALTY_MAX 4
+
+/* Number of observing count to judge whether EQMID may be increase.
+ * Those count can convert in time by following formula:
+ *    Time [ms] = (Count - abrQualityModeID) * LDAC_ABR_OBSERVING_TIME_MS
+ *    where abrQualityModeID is the value which converted EQMID by aEqmidToAbrQualityModeID[].
+ * Therefore, using the default value of 12, the observation time in each abrQualityModeID is
+ * as follows:
+ *       ----------------------------------------------------
+ *      | abrQualityModeID     |  0  |  1  |  2  |  3  |  4  |
+ *      | observation time [s] |  6  |  5  |  4  |  3  |  2  |
+ *       ----------------------------------------------------
+ */
+#define LDAC_ABR_OBSERVING_COUNT_TO_JUDGE_INC_QUALITY 12
+#define LDAC_ABR_OBSERVING_COUNT_FOR_INIT 6 /* = 3sec. keep same EQMID in first 3sec */
+/* Default value for thresholds */
+#define LDAC_ABR_THRESHOLD_CRITICAL_DEFAULT 6
+#define LDAC_ABR_THRESHOLD_DANGEROUSTREND_DEFAULT 4
+#define LDAC_ABR_THRESHOLD_SAFETY_FOR_HQSQ_DEFAULT 2
+/* Number of steady state count to judge */
+#define LDAC_ABR_NUM_STEADY_STATE_TO_JUDGE_STEADY 3
+/* Number of steady state count to reset for LDACBT_EQMID_HQ */
+#define LDAC_ABR_NUM_STEADY_STATE_TO_RESET_PENALTY_FOR_HQ 60
+
+
+typedef struct _tx_queue_param
+{
+    unsigned char *pHist;
+    unsigned int szHist;
+    int  sum;
+    unsigned int  cnt;
+    unsigned int idx;
+} TxQ_INFO;
+
+typedef struct _ldacbt_abr_param
+{
+    TxQ_INFO TxQD_Info;
+    int  cntToIncQuality;
+    int  nSteadyState;
+    int  nPenalty;
+    int  abrQualityModeIdSteady;
+    unsigned int  numToEvaluate;
+    /* thresholds */
+    unsigned int  thCritical;
+    unsigned int  thDangerousTrend;
+    unsigned int  thSafety4HQSQ;
+} LDAC_ABR_PARAMS;
+
+#define clear_data(ptr, n) memset(ptr, 0, n)
+
+#ifdef LOCAL_DEBUG
+#include <android/log.h>
+#define ABRDBG(fmt, ... ) \
+    __android_log_print( ANDROID_LOG_INFO, "******** LDAC ABR ********",\
+            "%s@%s:%d::"fmt, __func__, __FILE__, __LINE__, ## __VA_ARGS__ )
+#else
+#define ABRDBG(fmt, ...)
+#endif /* LOCAL_DEBUG */
+
+/* A table for converting EQMID to abrQualityModeID which is sorted in descending order by bit rate.
+ * The relationship between EQMID, bit rate and abrQualityModeID when the sampling frequency is
+ * 96 kHz is as follows:
+ *       ----------------------------------------------------
+ *      | EQMID                |  0  |  1  |  2  |  3  |  4  |
+ *      | bit rate [kbps]      | 990 | 660 | 330 | 492 | 396 |
+ *      | abrQualityModeID     |  0  |  1  |  4  |  2  |  3  |
+ *       ----------------------------------------------------
+ */
+static const int aEqmidToAbrQualityModeID[]={ 0, 1, 4, 2, 3};
+static const int sizeOfEqmidToBitrateSortedIdTable = (int)(sizeof(aEqmidToAbrQualityModeID)
+                                                     / sizeof(aEqmidToAbrQualityModeID[0]));
+
+/* Get LDAC ABR handle */
+HANDLE_LDAC_ABR ldac_ABR_get_handle(void)
+{
+    HANDLE_LDAC_ABR hLdacAbr;
+    ABRDBG( "" );
+    if ((hLdacAbr = (HANDLE_LDAC_ABR)malloc(sizeof(LDAC_ABR_PARAMS))) == NULL) {
+        ABRDBG( "[ERR] Failed to allocate memory for handle." );
+        return NULL;
+    }
+    hLdacAbr->TxQD_Info.pHist = NULL;
+    return hLdacAbr;
+}
+
+/* Free LDAC ABR handle */
+void ldac_ABR_free_handle(HANDLE_LDAC_ABR hLdacAbr)
+{
+    ABRDBG( "" );
+    if (hLdacAbr != NULL) {
+        if (hLdacAbr->TxQD_Info.pHist) {
+            free(hLdacAbr->TxQD_Info.pHist);
+        }
+        free(hLdacAbr);
+    }
+}
+
+/* Initialize LDAC ABR */
+int ldac_ABR_Init( HANDLE_LDAC_ABR hLdacAbr, unsigned int interval_ms )
+{
+    ABRDBG( "hLdacAbr:0x%x, interval_ms:%u", (unsigned int)hLdacAbr, interval_ms );
+    if (hLdacAbr == NULL) return -1;
+    if (interval_ms == 0) return -1;
+    if (interval_ms > LDAC_ABR_OBSERVING_TIME_MS) return -1;
+
+    hLdacAbr->numToEvaluate = LDAC_ABR_OBSERVING_TIME_MS / interval_ms;
+    hLdacAbr->TxQD_Info.sum = 0;
+    hLdacAbr->TxQD_Info.cnt = 0;
+    hLdacAbr->TxQD_Info.idx = 0;
+    hLdacAbr->TxQD_Info.szHist = hLdacAbr->numToEvaluate + 1;
+    if (hLdacAbr->TxQD_Info.pHist) free(hLdacAbr->TxQD_Info.pHist);
+    if ((hLdacAbr->TxQD_Info.pHist =
+            (unsigned char*)malloc(hLdacAbr->TxQD_Info.szHist * sizeof(unsigned char))) == NULL){
+        return -1;
+    }
+    clear_data(hLdacAbr->TxQD_Info.pHist, hLdacAbr->TxQD_Info.szHist * sizeof(unsigned char));
+
+    hLdacAbr->nSteadyState = 0;
+    hLdacAbr->nPenalty = 1;
+    hLdacAbr->abrQualityModeIdSteady = aEqmidToAbrQualityModeID[LDACBT_EQMID_HQ];
+    hLdacAbr->cntToIncQuality = LDAC_ABR_OBSERVING_COUNT_FOR_INIT;
+    /* thresholds */
+    hLdacAbr->thCritical = LDAC_ABR_THRESHOLD_CRITICAL_DEFAULT;
+    hLdacAbr->thDangerousTrend = LDAC_ABR_THRESHOLD_DANGEROUSTREND_DEFAULT;
+    hLdacAbr->thSafety4HQSQ = LDAC_ABR_THRESHOLD_SAFETY_FOR_HQSQ_DEFAULT;
+
+    return 0;
+}
+
+/* Setup thresholds for LDAC ABR */
+int ldac_ABR_set_thresholds( HANDLE_LDAC_ABR hLdacAbr, unsigned int thCritical,
+                        unsigned int thDangerousTrend, unsigned int thSafety4HQSQ )
+{
+    ABRDBG( "thCritical=%u, thDangerousTrend=%u, thSafety4HQSQ=%u",
+             thCritical, thDangerousTrend, thSafety4HQSQ);
+    if (hLdacAbr == NULL) return -1;
+    if (thCritical < thDangerousTrend) return -1;
+    if (thDangerousTrend < thSafety4HQSQ) return -1;
+    hLdacAbr->thCritical = thCritical;
+    hLdacAbr->thDangerousTrend = thDangerousTrend;
+    hLdacAbr->thSafety4HQSQ = thSafety4HQSQ;
+    return 0;
+}
+
+/* LDAC ABR main process */
+int ldac_ABR_Proc( HANDLE_LDAC_BT hLDAC, HANDLE_LDAC_ABR hLdacAbr,
+              unsigned int TxQueueDepth, unsigned int flagEnable)
+{
+    int nStepsToChangeEQMID, abrQualityModeID, eqmid, i;
+    unsigned int TxQD_curr, TxQD_prev;
+#ifdef LOCAL_DEBUG
+    int qd, TxQ; // for debug
+#endif
+
+    if (hLDAC == NULL) return -1;
+    if (hLdacAbr == NULL) return -1;
+
+    eqmid = ldacBT_get_eqmid(hLDAC);
+    abrQualityModeID = -1;
+    if ((LDACBT_EQMID_HQ <= eqmid) && (eqmid < sizeOfEqmidToBitrateSortedIdTable)) {
+        abrQualityModeID = aEqmidToAbrQualityModeID[eqmid];
+    }
+#ifdef LOCAL_DEBUG
+    ABRDBG( "[LDAC ABR] - abrQualityModeID : %d -- eqmid : %d -- TxQue : %d --------------",
+            abrQualityModeID, eqmid, TxQueueDepth);
+#endif
+    /* check for the situation when unsupported eqmid was return from ldacBT_get_eqmid(). */
+    if (abrQualityModeID < 0) return eqmid; /* return current eqmid. */
+
+    /* update */
+    TxQD_curr = TxQueueDepth;
+    if ((i = hLdacAbr->TxQD_Info.idx - 1) < 0 ) i = hLdacAbr->TxQD_Info.szHist - 1;
+    TxQD_prev = hLdacAbr->TxQD_Info.pHist[i];
+
+    hLdacAbr->TxQD_Info.sum -= hLdacAbr->TxQD_Info.pHist[hLdacAbr->TxQD_Info.idx];
+    hLdacAbr->TxQD_Info.pHist[hLdacAbr->TxQD_Info.idx] = (unsigned char)TxQD_curr;
+    if (++hLdacAbr->TxQD_Info.idx >= hLdacAbr->TxQD_Info.szHist) hLdacAbr->TxQD_Info.idx = 0;
+
+    hLdacAbr->TxQD_Info.sum += TxQD_curr;
+    ++hLdacAbr->TxQD_Info.cnt;
+
+#ifdef LOCAL_DEBUG
+    qd  = (abrQualityModeID    * 100000000);
+    qd += (hLdacAbr->nPenalty  *   1000000);
+    qd += (hLdacAbr->cntToIncQuality *1000);
+    qd += (hLdacAbr->nSteadyState);
+    TxQ = TxQD_prev * 100 + TxQD_curr;
+#endif
+
+    /* judge */
+    nStepsToChangeEQMID = 0;
+    if (TxQD_curr >= hLdacAbr->thCritical) {
+        /* for Critical situation */
+        ABRDBG("Critical: %d, %d", TxQ, qd);
+        nStepsToChangeEQMID = -1;
+        if ((eqmid == LDACBT_EQMID_HQ) || (eqmid == LDACBT_EQMID_SQ)) {
+            nStepsToChangeEQMID = -2;
+        }
+    }
+    else if ((TxQD_curr > hLdacAbr->thDangerousTrend) && (TxQD_curr > TxQD_prev)) {
+        ABRDBG("Dangerous: %d, %d", TxQ, qd);
+        nStepsToChangeEQMID = -1;
+    }
+    else if ((TxQD_curr > hLdacAbr->thSafety4HQSQ) &&
+             ((eqmid == LDACBT_EQMID_HQ) || (eqmid == LDACBT_EQMID_SQ))) {
+        ABRDBG("Safety4HQSQ: %d, %d", TxQ, qd);
+        nStepsToChangeEQMID = -1;
+    }
+    else if (hLdacAbr->TxQD_Info.cnt >= hLdacAbr->numToEvaluate) {
+        int ave10;
+        hLdacAbr->TxQD_Info.cnt = hLdacAbr->numToEvaluate;
+        /* eanble average process */
+        ave10 = (hLdacAbr->TxQD_Info.sum * 10) / hLdacAbr->TxQD_Info.cnt;
+
+        if (ave10 > 15) { /* if average of TxQue_Count in 0.5[s] was larger than 1.5 */
+            ABRDBG("ave: %d, %d, %d", TxQ, qd, ave10);
+            nStepsToChangeEQMID = -1;
+        }
+        else {
+            ++hLdacAbr->nSteadyState;
+#ifdef LOCAL_DEBUG
+            qd  = (abrQualityModeID    * 100000000);
+            qd += (hLdacAbr->nPenalty  *   1000000);
+            qd += (hLdacAbr->cntToIncQuality *1000);
+            qd += (hLdacAbr->nSteadyState);
+#endif
+
+            if (hLdacAbr->TxQD_Info.sum == 0) {
+                if (--hLdacAbr->cntToIncQuality <= 0) {
+                    ABRDBG("inc1: %d, %d, %d", TxQ, qd, ave10);
+                    nStepsToChangeEQMID = 1;
+                }
+                else {
+                    ABRDBG("reset: %d, %d, %d", TxQ, qd, ave10);
+                    hLdacAbr->TxQD_Info.cnt = 0; // reset the number of sample for average proc.
+                }
+            }
+            else {
+                ABRDBG( "reset cntToIncQuality, %d,%d, %d", TxQ,qd, ave10);
+                hLdacAbr->cntToIncQuality = LDAC_ABR_OBSERVING_COUNT_TO_JUDGE_INC_QUALITY
+                                            - 2 * abrQualityModeID;
+                if (abrQualityModeID >= hLdacAbr->abrQualityModeIdSteady) {
+                    hLdacAbr->cntToIncQuality *= hLdacAbr->nPenalty;
+                }
+            }
+        }
+    }
+#ifdef LOCAL_DEBUG
+    else {
+        ABRDBG("Nothing %d, hLdacAbr->TxQD_Info.cnt %u", TxQ, hLdacAbr->TxQD_Info.cnt);
+    }
+#endif
+    if (flagEnable) {
+        if (nStepsToChangeEQMID) {
+            int abrQualityModeIDNew;
+            if (nStepsToChangeEQMID < 0) {
+                for (i = 0; i > nStepsToChangeEQMID; --i) {
+                    if (ldacBT_alter_eqmid_priority(hLDAC, LDACBT_EQMID_INC_CONNECTION)) {
+#ifdef LOCAL_DEBUG
+                        int err;
+                        err = ldacBT_get_error_code(hLDAC);
+                        ABRDBG("Info@%d : %d ,%d, %d", __LINE__,
+                               LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err), LDACBT_BLOCK_ERR(err));
+#endif
+                        break;// EQMID was already the ID of the highest connectivity.
+                    }
+                }
+
+                eqmid = ldacBT_get_eqmid(hLDAC);
+                abrQualityModeIDNew = abrQualityModeID;
+                if (eqmid >= 0) {
+                    if (eqmid < sizeOfEqmidToBitrateSortedIdTable) {
+                        abrQualityModeIDNew = aEqmidToAbrQualityModeID[eqmid];
+                    }
+                }
+
+                if (hLdacAbr->nSteadyState < LDAC_ABR_NUM_STEADY_STATE_TO_JUDGE_STEADY) {
+                    hLdacAbr->abrQualityModeIdSteady = abrQualityModeIDNew - 1;
+                    if (hLdacAbr->abrQualityModeIdSteady < 0) hLdacAbr->abrQualityModeIdSteady = 0;
+                    hLdacAbr->nPenalty *= 2;
+                    if(hLdacAbr->nPenalty > LDAC_ABR_PENALTY_MAX) {
+                        hLdacAbr->nPenalty = LDAC_ABR_PENALTY_MAX; // MAX PENALTY
+                    }
+                }
+            }
+            else {
+                if (ldacBT_alter_eqmid_priority( hLDAC, LDACBT_EQMID_INC_QUALITY )) {
+#ifdef LOCAL_DEBUG
+                    int err;
+                    err = ldacBT_get_error_code(hLDAC);
+                    ABRDBG("Info@%d : %d ,%d, %d", __LINE__,
+                            LDACBT_API_ERR(err), LDACBT_HANDLE_ERR(err), LDACBT_BLOCK_ERR(err));
+#endif
+                    ;// EQMID was already the ID of the highest sound quality.
+                }
+                eqmid = ldacBT_get_eqmid(hLDAC);
+                abrQualityModeIDNew = abrQualityModeID;
+                if (eqmid >= 0) {
+                    if (eqmid < sizeOfEqmidToBitrateSortedIdTable) {
+                        abrQualityModeIDNew = aEqmidToAbrQualityModeID[eqmid];
+                    }
+                }
+                if (abrQualityModeIDNew < hLdacAbr->abrQualityModeIdSteady) {
+                    hLdacAbr->nPenalty = 1;
+                }
+                if (abrQualityModeIDNew == aEqmidToAbrQualityModeID[0]) { /* for HQ */
+                    if (hLdacAbr->nSteadyState > LDAC_ABR_NUM_STEADY_STATE_TO_RESET_PENALTY_FOR_HQ) {
+                        hLdacAbr->nPenalty = 1;
+                    }
+                }
+            }
+
+            hLdacAbr->nSteadyState = 0;
+            // reset the number of sample for average proc.
+            hLdacAbr->TxQD_Info.cnt = 0;
+            hLdacAbr->cntToIncQuality = LDAC_ABR_OBSERVING_COUNT_TO_JUDGE_INC_QUALITY
+                                        - 2 * abrQualityModeIDNew;
+            if (hLdacAbr->cntToIncQuality <= 0) {
+                // set minimum value.  e1 f == 0.5[s]
+                hLdacAbr->cntToIncQuality = 1;
+            }
+            hLdacAbr->cntToIncQuality *= hLdacAbr->nPenalty;
+            ABRDBG("EQMID NOW %d", eqmid);
+        }
+    }
+#ifdef LOCAL_DEBUG
+    else if (TxQueueDepth) {
+        ABRDBG("flagEnable false: %d ,%d", TxQ, qd);
+    }
+#endif
+
+    return eqmid;
+}
diff --git a/src/ldaclib_api.c b/src/ldaclib_api.c
index d15cae2..4c54407 100644
--- a/src/ldaclib_api.c
+++ b/src/ldaclib_api.c
@@ -456,6 +456,20 @@
 static const int saa_encode_setting_ldac[LDAC_ENC_NSETTING][LDAC_ENC_NPROPERTY] = {
     {0, 512,  17,   0,  28,  44,   8,  24,   0},
     {0, 256,  17,   0,  28,  44,   6,  22,   0},
+#ifdef MODIFY_LDAC_ENC_SETTING_FOR_ABR_DEBUG  // See file "ldacBT_abr.h" for description
+    {0, 164,  16,   0,  18,  32,   7,  23,   0},
+    {0, 110,   8,   0,  16,  32,  10,  31,   0},
+    {0,  82,   6,   0,  16,  32,  12,  31,   0},
+    {0,  66,   4,   0,  14,  26,  12,  31,   0},
+    {0,  54,   2,   0,  14,  26,  12,  31,   0},
+    {0,  46,   2,   1,  10,  26,  12,  31,   0},
+    {0,  40,   2,   2,  10,  26,  12,  31,   0},
+    {0,  36,   2,   2,   8,  26,  12,  31,   0},
+    {0,  32,   2,   2,   8,  26,  16,  31,   0},
+    {0,  30,   2,   2,   4,  26,  16,  31,   0},
+    {0,  26,   2,   3,   4,  26,  16,  31,   0},
+    {0,  24,   2,   3,   4,  26,  16,  31,   0},
+#else
     {0, 164,  16,   0,  18,  32,   7,  23,   0},
     {0, 110,  13,   0,  16,  32,  10,  31,   0},
     {0,  82,  12,   0,  16,  32,  12,  31,   0},
@@ -468,6 +482,7 @@
     {0,  30,   5,   2,   4,  26,  16,  31,   0},
     {0,  26,   4,   3,   4,  26,  16,  31,   0},
     {0,  24,   3,   3,   4,  26,  16,  31,   0},
+#endif
     {0,  22,   2,   3,   4,  26,  16,  31,   0},
 };