Home | History | Annotate | Download | only in libaudio
      1 /*
      2 ** Copyright 2010, The Android Open-Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "AudioPostProcessor"
     19 #include <fcntl.h>
     20 #include <utils/Log.h>
     21 #include "AudioHardware.h"
     22 #include "AudioPostProcessor.h"
     23 #include <sys/stat.h>
     24 #include "mot_acoustics.h"
     25 // hardware specific functions
     26 extern uint16_t HC_CTO_AUDIO_MM_PARAMETER_TABLE[];
     27 ///////////////////////////////////
     28 // Some logging #defines
     29 #define ECNS_LOG_ENABLE_OFFSET 1 // 2nd word of the configuration buffer
     30 #define ECNS_LOGGING_BITS 0xBFFF // 15 possible logpoints
     31 
     32 #define MOT_LOG_DELIMITER_START  0xFEED
     33 #define MOT_LOG_DELIMITER_END    0xF00D
     34 #define BASIC_DOCK_PROP_VALUE    0
     35 
     36 #define ECNSLOGPATH "/data/ecns"
     37 #define DOCK_PROP_PATH "/sys/class/switch/dock/dock_prop"
     38 
     39 #ifndef ARRAY_SIZE
     40 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
     41 #endif
     42 
     43 //#define DEBUG_TIMING
     44 #ifdef DEBUG_TIMING
     45 struct timeval mtv1, mtv2, mtv3, mtv4, mtv5, mtv6, mtv7, mtv8;
     46 #define GETTIMEOFDAY gettimeofday
     47 #else
     48 #define GETTIMEOFDAY(a,b)
     49 #endif
     50 
     51 namespace android_audio_legacy {
     52 
     53 AudioPostProcessor::AudioPostProcessor() :
     54     mEcnsScratchBuf(0), mLogNumPoints(0),  mEcnsDlBuf(0), mEcnsDlBufSize(0), mEcnsThread(0)
     55 {
     56     LOGD("%s",__FUNCTION__);
     57 
     58     // One-time CTO Audio configuration
     59     mAudioMmEnvVar.cto_audio_mm_param_block_ptr              = HC_CTO_AUDIO_MM_PARAMETER_TABLE;
     60     mAudioMmEnvVar.cto_audio_mm_pcmlogging_buffer_block_ptr  = mPcmLoggingBuf;
     61     mAudioMmEnvVar.pcmlogging_buffer_block_size              = ARRAY_SIZE(mPcmLoggingBuf);
     62     mAudioMmEnvVar.cto_audio_mm_runtime_param_mem_ptr        = mRuntimeParam;
     63     mAudioMmEnvVar.cto_audio_mm_static_memory_block_ptr      = mStaticMem;
     64     mAudioMmEnvVar.cto_audio_mm_scratch_memory_block_ptr     = mScratchMem;
     65     mAudioMmEnvVar.accy = CTO_AUDIO_MM_ACCY_INVALID;
     66     mAudioMmEnvVar.sample_rate = CTO_AUDIO_MM_SAMPL_44100;
     67 
     68     mEcnsThread = new EcnsThread();
     69     // Initial conditions for EC/NS
     70     stopEcns();
     71 }
     72 
     73 AudioPostProcessor::~AudioPostProcessor()
     74 {
     75     if (mEcnsRunning) {
     76         LOGD("%s",__FUNCTION__);
     77         enableEcns(0);
     78     }
     79 }
     80 
     81 uint32_t AudioPostProcessor::convOutDevToCTO(uint32_t outDev)
     82 {
     83     int32_t dock_prop = 0;
     84     // Only loudspeaker and audio docks are currently in this table
     85     switch (outDev) {
     86        case CPCAP_AUDIO_OUT_SPEAKER:
     87            return CTO_AUDIO_MM_ACCY_LOUDSPEAKER;
     88        case CPCAP_AUDIO_OUT_ANLG_DOCK_HEADSET:
     89            dock_prop = read_dock_prop(DOCK_PROP_PATH);
     90            if ((dock_prop < 0) || (dock_prop == BASIC_DOCK_PROP_VALUE)) {
     91                // Basic dock, or error getting the dock ID
     92                return CTO_AUDIO_MM_ACCY_INVALID;
     93 	   }
     94            else // speaker dock
     95                return CTO_AUDIO_MM_ACCY_DOCK;
     96        default:
     97            return CTO_AUDIO_MM_ACCY_INVALID;
     98     }
     99 }
    100 
    101 uint32_t AudioPostProcessor::convRateToCto(uint32_t rate)
    102 {
    103     switch (rate) {
    104         case 44100: // Most likely.
    105             return CTO_AUDIO_MM_SAMPL_44100;
    106         case 8000:
    107             return CTO_AUDIO_MM_SAMPL_8000;
    108         case 11025:
    109             return CTO_AUDIO_MM_SAMPL_11025;
    110         case 12000:
    111             return CTO_AUDIO_MM_SAMPL_12000;
    112         case 16000:
    113             return CTO_AUDIO_MM_SAMPL_16000;
    114         case 22050:
    115             return CTO_AUDIO_MM_SAMPL_22050;
    116         case 24000:
    117             return CTO_AUDIO_MM_SAMPL_24000;
    118         case 32000:
    119             return CTO_AUDIO_MM_SAMPL_32000;
    120         case 48000:
    121             return CTO_AUDIO_MM_SAMPL_48000;
    122         default:
    123             return CTO_AUDIO_MM_SAMPL_44100;
    124     }
    125 }
    126 
    127 void AudioPostProcessor::configMmAudio()
    128 {
    129     if (mAudioMmEnvVar.accy != CTO_AUDIO_MM_ACCY_INVALID) {
    130         LOGD("Configure CTO Audio MM processing");
    131         // fetch the corresponding runtime audio parameter
    132         api_cto_audio_mm_param_parser(&(mAudioMmEnvVar), (int16_t *)0, (int16_t *)0);
    133         // Initialize algorithm static memory
    134         api_cto_audio_mm_init(&(mAudioMmEnvVar), (int16_t *)0, (int16_t *)0);
    135     } else {
    136         LOGD("CTO Audio MM processing is disabled.");
    137     }
    138 }
    139 
    140 void AudioPostProcessor::enableEcns(int value)
    141 {
    142     if (mEcnsEnabled!=value) {
    143         LOGD("enableEcns() new %08x old %08x)", value, mEcnsEnabled);
    144         mEcnsThread->broadcastReadCond();
    145         mEcnsThread->requestExitAndWait();
    146         stopEcns();
    147         cleanupEcns();
    148         mEcnsEnabled = value;
    149     }
    150 }
    151 
    152 void AudioPostProcessor::setAudioDev(struct cpcap_audio_stream *outDev,
    153                                      struct cpcap_audio_stream *inDev,
    154                                      bool is_bt, bool is_bt_ec, bool is_spdif)
    155 {
    156     int32_t dock_prop = 0;
    157     uint32_t mm_accy = convOutDevToCTO(outDev->id);
    158     Mutex::Autolock lock(mMmLock);
    159 
    160     if (is_bt) {
    161         if (is_bt_ec)
    162             mEcnsMode = CTO_AUDIO_USECASE_NB_BLUETOOTH_WITH_ECNS;
    163         else
    164             mEcnsMode = CTO_AUDIO_USECASE_NB_BLUETOOTH_WITHOUT_ECNS;
    165     } else if (is_spdif) // May need a more complex check here for HDMI vs. others
    166         mEcnsMode = CTO_AUDIO_USECASE_NB_ACCY_1;
    167     else if (outDev->id==CPCAP_AUDIO_OUT_HEADSET && inDev->id==CPCAP_AUDIO_IN_MIC1)
    168         mEcnsMode = CTO_AUDIO_USECASE_NB_HEADSET_WITH_HANDSET_MIC;
    169     else if (outDev->id==CPCAP_AUDIO_OUT_HEADSET)
    170         mEcnsMode = CTO_AUDIO_USECASE_NB_HEADSET;
    171     else if (outDev->id==CPCAP_AUDIO_OUT_ANLG_DOCK_HEADSET) {
    172         dock_prop = read_dock_prop(DOCK_PROP_PATH);
    173         if ((dock_prop < 0) || (dock_prop == BASIC_DOCK_PROP_VALUE))
    174             // Basic dock, or error getting the dock ID
    175             mEcnsMode = CTO_AUDIO_USECASE_NB_ACCY_1;
    176         else
    177             // Speaker Dock
    178             mEcnsMode = CTO_AUDIO_USECASE_NB_DEDICATED_DOCK;
    179     }
    180     else
    181         mEcnsMode = CTO_AUDIO_USECASE_NB_SPKRPHONE;
    182 
    183     if (mEcnsEnabled) {
    184         // We may need to reset the EC/NS if the output device changed.
    185         stopEcns();
    186     }
    187 
    188     LOGV("setAudioDev %d", outDev->id);
    189     if (mm_accy != mAudioMmEnvVar.accy) {
    190         mAudioMmEnvVar.accy = mm_accy;
    191         configMmAudio();
    192     }
    193 }
    194 
    195 // Setting the HW sampling rate may require reconfiguration of audio processing.
    196 void AudioPostProcessor::setPlayAudioRate(int sampRate)
    197 {
    198     uint32_t rate = convRateToCto(sampRate);
    199     Mutex::Autolock lock(mMmLock);
    200 
    201     LOGD("AudioPostProcessor::setPlayAudioRate %d", sampRate);
    202     if (rate != mAudioMmEnvVar.sample_rate) {
    203         mAudioMmEnvVar.sample_rate = rate;
    204         configMmAudio();
    205     }
    206 }
    207 
    208 void AudioPostProcessor::doMmProcessing(void * buffer, int numSamples)
    209 {
    210     Mutex::Autolock lock(mMmLock);
    211 
    212     if (mAudioMmEnvVar.accy != CTO_AUDIO_MM_ACCY_INVALID &&
    213         !mEcnsEnabled) {
    214         // Apply the CTO audio effects in-place.
    215         mAudioMmEnvVar.frame_size = numSamples;
    216         api_cto_audio_mm_main(&mAudioMmEnvVar, (int16_t *)buffer, (int16_t *)buffer);
    217     }
    218 }
    219 
    220 int AudioPostProcessor::getEcnsRate (void)
    221 {
    222     return mEcnsRate;
    223 }
    224 
    225 void AudioPostProcessor::initEcns(int rate, int bytes)
    226 {
    227     LOGD("%s",__FUNCTION__);
    228     CTO_AUDIO_USECASES_CTRL mode;
    229     Mutex::Autolock lock(mEcnsBufLock);
    230 
    231     if (rate != 8000 && rate != 16000) {
    232         LOGW("Invalid rate for EC/NS, disabling");
    233         mEcnsEnabled = 0;
    234         mEcnsRunning = 0;
    235         return;
    236     }
    237     mode = mEcnsMode;
    238     mEcnsRate = rate;
    239     if (mEcnsRate==16000) {
    240        // Offset to the 16K (WB) block in the coefficients file
    241        mode = CTO_AUDIO_USECASES_CTRL(mode + CTO_AUDIO_USECASE_WB_HANDSET);
    242     }
    243     LOGD("%s for mode %d at %d size %d",__FUNCTION__, mode, mEcnsRate, bytes);
    244     mEcnsCtrl.framesize = bytes/2;
    245     mEcnsCtrl.micFlag = 0; // 0- one mic.  1- dual mic. 2- three mic.
    246     mEcnsCtrl.digital_mode = (rate == 8000) ? 0 : 1;  // 8K or 16K
    247     mEcnsCtrl.usecase = mode;
    248     mMemBlocks.staticMemory_1 = mStaticMemory_1;
    249     mMemBlocks.staticMemory_2 = NULL;
    250     mMemBlocks.mot_datalog = mMotDatalog;
    251     mMemBlocks.gainTableMemory = mParamTable;
    252 
    253     FILE * fp = fopen("/system/etc/voip_aud_params.bin", "r");
    254     if (fp) {
    255         if (fread(mParamTable, sizeof(mParamTable), 1, fp) < 1) {
    256             LOGE("Cannot read VOIP parameter file.  Disabling EC/NS.");
    257             fclose(fp);
    258             mEcnsEnabled = 0;
    259             mEcnsRunning = 0;
    260             return;
    261         }
    262         fclose(fp);
    263     }
    264     else {
    265         LOGE("Cannot open VOIP parameter file.  Disabling EC/NS.");
    266         mEcnsEnabled = 0;
    267         mEcnsRunning = 0;
    268         return;
    269     }
    270 
    271     mEcnsRunning = 1;
    272     mEcnsOutBuf = 0;
    273     mEcnsOutBufSize = 0;
    274     mEcnsOutBufReadOffset = 0;
    275 
    276     // Send setup parameters to the EC/NS module, init the module.
    277     API_MOT_SETUP(&mEcnsCtrl, &mMemBlocks);
    278     API_MOT_INIT(&mEcnsCtrl, &mMemBlocks);
    279 }
    280 
    281 void AudioPostProcessor::stopEcns (void)
    282 {
    283     AutoMutex lock(mEcnsBufLock);
    284     if (mEcnsRunning) {
    285         LOGD("%s",__FUNCTION__);
    286         mEcnsRunning = 0;
    287     }
    288 }
    289 
    290 void AudioPostProcessor::cleanupEcns(void)
    291 {
    292     AutoMutex lock(mEcnsBufLock);
    293     mEcnsRate = 0;
    294     if (mEcnsScratchBuf) {
    295         free(mEcnsScratchBuf);
    296         mEcnsScratchBuf = 0;
    297     }
    298     mEcnsScratchBufSize = 0;
    299     mEcnsOutFd = -1;
    300 
    301     if (mEcnsDlBuf) {
    302        free(mEcnsDlBuf);
    303        mEcnsDlBuf = 0;
    304     }
    305     mEcnsDlBufSize = 0;
    306     // In case write() is blocked, set it free.
    307     mEcnsBufCond.signal();
    308 
    309     ecnsLogToFile();
    310 }
    311 
    312 
    313 // Returns: Bytes written (actually "to-be-written" by EC/NS thread).
    314 int AudioPostProcessor::writeDownlinkEcns(int fd, void * buffer, bool stereo,
    315                                           int bytes, Mutex *fdLock)
    316 {
    317     int written = 0;
    318 
    319     // write directly to pcm out driver if only NS is enabled
    320     if (!(mEcnsEnabled & AEC)) {
    321         if (fd >= 0) {
    322             fdLock->lock();
    323             ::write(fd, buffer, bytes);
    324             fdLock->unlock();
    325         }
    326         return bytes;
    327     }
    328 
    329     mEcnsBufLock.lock();
    330     if (mEcnsEnabled && !mEcnsRunning) {
    331         long usecs = 20*1000;
    332         // Give the read thread a chance to catch up.
    333         LOGV("%s: delay %d msecs for ec/ns to start",__FUNCTION__, (int)(usecs/1000));
    334         mEcnsBufLock.unlock();
    335         usleep(usecs);
    336         mEcnsBufLock.lock();
    337         written = bytes;  // Pretend all data was consumed even if ecns isn't running
    338     }
    339     if (mEcnsRunning) {
    340         // Only run through here after initEcns has been done by read thread.
    341         mEcnsOutFd = fd;
    342         mEcnsOutBuf = buffer;
    343         mEcnsOutBufSize = bytes;
    344         mEcnsOutBufReadOffset = 0;
    345         mEcnsOutFdLockp = fdLock;
    346         mEcnsOutStereo = stereo;
    347         if (mEcnsBufCond.waitRelative(mEcnsBufLock, seconds(1)) != NO_ERROR) {
    348             LOGE("%s: Capture thread is stalled.", __FUNCTION__);
    349         }
    350         if (mEcnsOutBufSize != 0)
    351             LOGD("%s: Buffer not consumed", __FUNCTION__);
    352         else
    353             written = bytes;  // All data consumed
    354     }
    355     mEcnsBufLock.unlock();
    356     return written;
    357 }
    358 
    359 // Returns: Bytes read.
    360 int AudioPostProcessor::read(int fd, void * buffer, int bytes, int rate)
    361 {
    362     if (mEcnsEnabled) {
    363         return mEcnsThread->readData(fd, buffer, bytes, rate, this);
    364     }
    365     ssize_t ret;
    366     ret = ::read(fd, buffer, bytes);
    367     if (ret < 0)
    368         LOGE("Error reading from audio in: %s", strerror(errno));
    369     return (int)ret;
    370 }
    371 
    372 // Returns: Bytes processed.
    373 int AudioPostProcessor::applyUplinkEcns(void * buffer, int bytes, int rate)
    374 {
    375     static int16 ul_gbuff2[160];
    376     int16_t *dl_buf;
    377     int16_t *ul_buf = (int16_t *)buffer;
    378     int dl_buf_bytes=0;
    379     // The write thread could have left us with one frame of data in the
    380     // driver when we started reading.
    381     static bool onetime;
    382 
    383     if (!mEcnsEnabled)
    384         return 0;
    385 
    386     LOGV("%s %d bytes at %d Hz",__FUNCTION__, bytes, rate);
    387     if (mEcnsEnabled && !mEcnsRunning) {
    388         initEcns(rate, bytes);
    389         onetime=true;
    390     }
    391 
    392     // In case the rate switched..
    393     if (mEcnsEnabled && rate != mEcnsRate) {
    394         stopEcns();
    395         initEcns(rate, bytes);
    396         onetime=true;
    397     }
    398 
    399     if (!mEcnsRunning) {
    400         LOGE("EC/NS failed to init, read returns.");
    401         if (mEcnsEnabled & AEC) {
    402             mEcnsBufCond.signal();
    403         }
    404         return -1;
    405     }
    406 
    407     // do not get downlink audio if only NS is enabled
    408     if (mEcnsEnabled & AEC) {
    409         mEcnsBufLock.lock();
    410         // Need a contiguous stereo playback buffer in the end.
    411         if (bytes*2 != mEcnsDlBufSize || !mEcnsDlBuf) {
    412             if (mEcnsDlBuf)
    413                 free(mEcnsDlBuf);
    414             mEcnsDlBuf = (int16_t*)malloc(bytes*2);
    415             if (mEcnsDlBuf)
    416                 mEcnsDlBufSize = bytes*2;
    417         }
    418         dl_buf = mEcnsDlBuf;
    419         if (!dl_buf) {
    420             mEcnsBufLock.unlock();
    421             return -1;
    422         }
    423 
    424         // Need to gather appropriate amount of downlink speech.
    425         // Take oldest scratch data first.  The scratch buffer holds fractions of buffers
    426         // that were too small for processing.
    427         if (mEcnsScratchBuf && mEcnsScratchBufSize) {
    428             dl_buf_bytes = mEcnsScratchBufSize > bytes ? bytes:mEcnsScratchBufSize;
    429             memcpy(dl_buf, mEcnsScratchBuf, dl_buf_bytes);
    430             //LOGD("Took %d bytes from mEcnsScratchBuf", dl_buf_bytes);
    431             mEcnsScratchBufSize -= dl_buf_bytes;
    432             if (mEcnsScratchBufSize==0) {
    433                 // This should always be true.
    434                 free(mEcnsScratchBuf);
    435                 mEcnsScratchBuf = 0;
    436                 mEcnsScratchBufSize = 0;
    437             }
    438         }
    439         // Take fresh data from write thread second.
    440         if (dl_buf_bytes < bytes) {
    441             int bytes_to_copy = mEcnsOutBufSize - mEcnsOutBufReadOffset;
    442             bytes_to_copy = bytes_to_copy + dl_buf_bytes > bytes?
    443                           bytes-dl_buf_bytes:bytes_to_copy;
    444             if (bytes_to_copy) {
    445                 memcpy((void *)((unsigned int)dl_buf+dl_buf_bytes),
    446                        (void *)((unsigned int)mEcnsOutBuf+mEcnsOutBufReadOffset),
    447                        bytes_to_copy);
    448                 dl_buf_bytes += bytes_to_copy;
    449             }
    450             //LOGD("Took %d bytes from mEcnsOutBuf.  Need %d more.", bytes_to_copy,
    451             //      bytes-dl_buf_bytes);
    452             mEcnsOutBufReadOffset += bytes_to_copy;
    453             if (mEcnsOutBufSize - mEcnsOutBufReadOffset < bytes) {
    454                 // We've depleted the output buffer, it's smaller than one uplink "frame".
    455                 // First take any unused data into scratch, then free the write thread.
    456                 if (mEcnsScratchBuf) {
    457                     LOGE("Memleak - coding error");
    458                     free(mEcnsScratchBuf);
    459                 }
    460                 if (mEcnsOutBufSize - mEcnsOutBufReadOffset > 0) {
    461                     if ((mEcnsScratchBuf=malloc(mEcnsOutBufSize - mEcnsOutBufReadOffset)) == 0) {
    462                         LOGE("%s: Alloc failed, scratch data lost.",__FUNCTION__);
    463                     } else {
    464                         mEcnsScratchBufSize = mEcnsOutBufSize - mEcnsOutBufReadOffset;
    465                         //LOGD("....store %d bytes into scratch buf %p",
    466                         //     mEcnsScratchBufSize, mEcnsScratchBuf);
    467                         memcpy(mEcnsScratchBuf,
    468                                (void *)((unsigned int)mEcnsOutBuf+mEcnsOutBufReadOffset),
    469                                mEcnsScratchBufSize);
    470                     }
    471                 }
    472                 mEcnsOutBuf = 0;
    473                 mEcnsOutBufSize = 0;
    474                 mEcnsOutBufReadOffset = 0;
    475                 //LOGD("Signal write thread - need data.");
    476                 mEcnsBufCond.signal();
    477             }
    478         }
    479 
    480         LOGV_IF(dl_buf_bytes < bytes, "%s:EC/NS Starved for downlink data. have %d need %d.",
    481              __FUNCTION__,dl_buf_bytes, bytes);
    482 
    483         mEcnsBufLock.unlock();
    484     } else {
    485         if (mEcnsDlBufSize < bytes * 2) {
    486            mEcnsDlBufSize = bytes * 2;
    487            mEcnsDlBuf = (int16_t *)realloc(mEcnsDlBuf, mEcnsDlBufSize);
    488         }
    489         dl_buf = mEcnsDlBuf;
    490     }
    491 
    492     // Pad downlink with zeroes as last resort.  We have to process the UL speech.
    493     if (dl_buf_bytes < bytes) {
    494         memset(&dl_buf[dl_buf_bytes/sizeof(int16_t)],
    495                0,
    496                bytes-dl_buf_bytes);
    497     }
    498 
    499     // Do Echo Cancellation
    500     GETTIMEOFDAY(&mtv4, NULL);
    501     API_MOT_LOG_RESET(&mEcnsCtrl, &mMemBlocks);
    502     if (mEcnsEnabled & AEC) {
    503         API_MOT_DOWNLINK(&mEcnsCtrl, &mMemBlocks, (int16*)dl_buf, (int16*)ul_buf, &(ul_gbuff2[0]));
    504     }
    505     API_MOT_UPLINK(&mEcnsCtrl, &mMemBlocks, (int16*)dl_buf, (int16*)ul_buf, &(ul_gbuff2[0]));
    506 
    507     // Playback the echo-cancelled speech to driver.
    508     // Include zero padding.  Our echo canceller needs a consistent path.
    509     if (mEcnsEnabled & AEC) {
    510         if (mEcnsOutStereo) {
    511             // Convert up to stereo, in place.
    512             for (int i = bytes/2-1; i >= 0; i--) {
    513                 dl_buf[i*2] = dl_buf[i];
    514                 dl_buf[i*2+1] = dl_buf[i];
    515             }
    516             dl_buf_bytes *= 2;
    517         }
    518         GETTIMEOFDAY(&mtv5, NULL);
    519         if (mEcnsOutFd != -1) {
    520             mEcnsOutFdLockp->lock();
    521             ::write(mEcnsOutFd, &dl_buf[0],
    522                     bytes*(mEcnsOutStereo?2:1));
    523             mEcnsOutFdLockp->unlock();
    524         }
    525     }
    526     // Do the CTO SuperAPI internal logging.
    527     // (Do this after writing output to avoid adding latency.)
    528     GETTIMEOFDAY(&mtv6, NULL);
    529     ecnsLogToRam(bytes);
    530     return bytes;
    531 }
    532 void AudioPostProcessor::ecnsLogToRam (int bytes)
    533 {
    534     uint16_t *logp;
    535     int mode = mEcnsMode + (mEcnsRate==16000?CTO_AUDIO_USECASE_WB_HANDSET:0);
    536     uint16_t *audioProfile = &mParamTable[AUDIO_PROFILE_PARAMETER_BLOCK_WORD16_SIZE*mode];
    537 
    538     if (audioProfile[ECNS_LOG_ENABLE_OFFSET] & ECNS_LOGGING_BITS) {
    539         if (!mLogBuf[0]) {
    540             mLogNumPoints = 0;
    541             mLogOffset = 0;
    542             LOGE("EC/NS AUDIO LOGGER CONFIGURATION:");
    543             LOGE("log enable %04X",
    544                 audioProfile[ECNS_LOG_ENABLE_OFFSET]);
    545             mkdir(ECNSLOGPATH, 00770);
    546             for (uint16_t i=1; i>0; i<<=1) {
    547                 if (i&ECNS_LOGGING_BITS&audioProfile[ECNS_LOG_ENABLE_OFFSET]) {
    548                    mLogNumPoints++;
    549                 }
    550             }
    551             LOGE("Number of log points is %d.", mLogNumPoints);
    552             logp = mMotDatalog;
    553             mLogSize = 10*60*50*bytes;
    554             for (int i=0; i<mLogNumPoints; i++) {
    555                 // Allocate 10 minutes of logging per point
    556                 mLogBuf[i]=(char *)malloc(mLogSize);
    557                 if (!mLogBuf[i]) {
    558                     LOGE("%s: Memory allocation failed.", __FUNCTION__);
    559                     for (int j=0; j<i; j++) {
    560                         free(mLogBuf[j]);
    561                         mLogBuf[j]=0;
    562                     }
    563                     return;
    564                 }
    565             }
    566         }
    567         if (mLogOffset+bytes > mLogSize)
    568             return;
    569         logp = mMotDatalog;
    570         for (int i=0; i<mLogNumPoints; i++) {
    571             if (mLogBuf[i]) {
    572                 mLogPoint[i] = logp[1];
    573                 memcpy(&mLogBuf[i][mLogOffset], &logp[4], logp[2]*sizeof(uint16_t));
    574                 logp += 4+logp[2];
    575             } else {
    576                 LOGE("EC/NS logging enabled, but memory not allocated");
    577             }
    578         }
    579         mLogOffset += bytes;
    580     }
    581 }
    582 
    583 void AudioPostProcessor::ecnsLogToFile()
    584 {
    585     if (mLogNumPoints && mLogOffset > 16000*2) {
    586         for (int i=0; i<mLogNumPoints; i++) {
    587             FILE * fp;
    588             char fname[80];
    589             sprintf(fname, ECNSLOGPATH"/log-0x%04X.pcm", mLogPoint[i]);
    590             fp = fopen((const char *)fname, "w");
    591             if (fp) {
    592                 LOGE("Writing %d bytes to %s", mLogOffset, fname);
    593                 fwrite(mLogBuf[i], mLogOffset, 1, fp);
    594                 fclose(fp);
    595             } else {
    596                 LOGE("Problem writing to %s", fname);
    597             }
    598         }
    599     }
    600     mLogOffset = 0;
    601 }
    602 
    603 int AudioPostProcessor::read_dock_prop(char const *path)
    604 {
    605     int fd = -1;
    606     const size_t SIZE = 7;
    607     static int already_warned = -1;
    608     char buffer[SIZE];
    609     /* the docks come with a property id AC000 for basic docks
    610        and AC002 for speaker docks, numbers might change, keeping
    611        them for now.
    612      */
    613     unsigned long int basic_dock_prop = 0xAC000;
    614     unsigned long int spkr_dock_prop;
    615 
    616     buffer[SIZE - 1] = '\0';
    617     fd = open(path, O_RDONLY);
    618     if (fd >= 0) {
    619         int amt = ::read(fd, buffer, SIZE-1);
    620         if (amt != SIZE-1) {
    621 	    LOGE("Incomplete dock property read, cannot validate dock");
    622 	    return -1;
    623         }
    624         spkr_dock_prop = strtoul(buffer, NULL, 16);
    625 	if (spkr_dock_prop <= 0) {
    626 	    LOGE("dock property conversion error");
    627 	    return -EINVAL;
    628         }
    629         close(fd);
    630         LOGV("buffer = %s, spkr_dock_prop = 0x%lX", buffer, spkr_dock_prop);
    631         spkr_dock_prop = spkr_dock_prop ^ basic_dock_prop;
    632         LOGV("dock_prop returned = %lX", spkr_dock_prop);
    633         return spkr_dock_prop;
    634     } else {
    635         if (already_warned == -1) {
    636             LOGE("read_dock_prop failed to open %s\n", path);
    637             already_warned = 1;
    638         }
    639         return -errno;
    640     }
    641 }
    642 // ---------------------------------------------------------------------------------------------
    643 // Echo Canceller thread
    644 // Needed to isolate the EC/NS module from scheduling jitter of it's clients.
    645 //
    646 AudioPostProcessor::EcnsThread::EcnsThread() :
    647     mReadBuf(0), mIsRunning(0)
    648 {
    649 }
    650 
    651 AudioPostProcessor::EcnsThread::~EcnsThread()
    652 {
    653 }
    654 
    655 int AudioPostProcessor::EcnsThread::readData(int fd, void * buffer, int bytes, int rate,
    656                                              AudioPostProcessor * pp)
    657 {
    658     LOGV("%s: read %d bytes at %d rate", __FUNCTION__, bytes, rate);
    659     Mutex::Autolock lock(mEcnsReadLock);
    660     mProcessor = pp;
    661     mFd = fd;
    662     mClientBuf = buffer;
    663     mReadSize = bytes;
    664     mRate = rate;
    665     if (!mIsRunning) {
    666         LOGD("Create (run) the ECNS thread");
    667         run("AudioPostProcessor::EcnsThread", ANDROID_PRIORITY_HIGHEST);
    668         mIsRunning = true;
    669     }
    670     mEcnsReadCond.signal();
    671     if (mEcnsReadCond.waitRelative(mEcnsReadLock, seconds(1)) != NO_ERROR) {
    672         LOGE("%s: ECNS thread is stalled.", __FUNCTION__);
    673         mClientBuf = 0;
    674         return -1;
    675     }
    676     return bytes;
    677 }
    678 
    679 bool AudioPostProcessor::EcnsThread::threadLoop()
    680 {
    681 #ifdef DEBUG_TIMING
    682     int count = 0;
    683     int small_jitter = 0;
    684     int medium_jitter = 0;
    685     int large_jitter = 0;
    686 #endif
    687     ssize_t ret1 = 0, ret2;
    688     struct timeval tv1, tv2;
    689     int  usecs;
    690     bool half_done = false;
    691     int ecnsStatus = 0;
    692 
    693     LOGD("%s: Enter thread loop size %d rate %d", __FUNCTION__,
    694                                           mReadSize, mRate);
    695 
    696     mReadBuf = (int16_t *) malloc(mReadSize);
    697     if (!mReadBuf)
    698         goto error;
    699 
    700     while (!exitPending() && ecnsStatus != -1) {
    701         GETTIMEOFDAY(&mtv1, NULL);
    702         if (!half_done)
    703             ret1 = ::read(mFd, mReadBuf, mReadSize/2);
    704         if(exitPending())
    705             goto error;
    706         GETTIMEOFDAY(&mtv2, NULL);
    707         ret2 = ::read(mFd, (char *)mReadBuf+mReadSize/2, mReadSize/2);
    708         if(exitPending())
    709             goto error;
    710         if (ret1 <= 0 || ret2 <= 0) {
    711             LOGE("%s: Problem reading.", __FUNCTION__);
    712             goto error;
    713         }
    714         GETTIMEOFDAY(&mtv3, NULL);
    715         mEcnsReadLock.lock();
    716         ecnsStatus = mProcessor->applyUplinkEcns(mReadBuf, mReadSize, mRate);
    717 
    718         // wait for client buffer if not ready
    719         if (!mClientBuf) {
    720             if(exitPending()) {
    721                 mEcnsReadLock.unlock();
    722                 goto error;
    723             }
    724             if (mEcnsReadCond.waitRelative(mEcnsReadLock, seconds(1)) != NO_ERROR) {
    725                 LOGE("%s: client stalled.", __FUNCTION__);
    726             }
    727         }
    728         if (mClientBuf && mReadSize) {
    729             // Give the buffer to the client.
    730             memcpy(mClientBuf, mReadBuf, mReadSize);
    731             // Avoid read overflow by reading before signaling the similar-priority read thread.
    732             ret1 = ::read(mFd, mReadBuf, mReadSize/2);
    733             half_done = true;
    734             GETTIMEOFDAY(&mtv7, NULL);
    735             mClientBuf = 0;
    736             mEcnsReadCond.signal();
    737         } else {
    738             half_done = false;
    739             LOGV("%s: Read overflow (ECNS sanity preserved)", __FUNCTION__);
    740         }
    741         mEcnsReadLock.unlock();
    742         GETTIMEOFDAY(&mtv8, NULL);
    743 
    744 #ifdef DEBUG_TIMING
    745 	count++;
    746         tv1.tv_sec = mtv1.tv_sec;
    747         tv1.tv_usec = mtv1.tv_usec;
    748         tv2.tv_sec = mtv8.tv_sec;
    749         tv2.tv_usec = mtv8.tv_usec;
    750         // Compare first and last timestamps
    751         tv2.tv_sec -= tv1.tv_sec;
    752         if(tv2.tv_usec < tv1.tv_usec) {
    753             tv2.tv_sec--;
    754             tv2.tv_usec = 1000000 + tv2.tv_usec - tv1.tv_usec;
    755         } else {
    756             tv2.tv_usec = tv2.tv_usec - tv1.tv_usec;
    757         }
    758         usecs = tv2.tv_usec + tv2.tv_sec*1000000;
    759         if (usecs > 25000) {
    760             if (usecs > 30000)
    761                 large_jitter++;
    762             else
    763                 medium_jitter++;
    764             LOGD("jitter: usecs = %d should be 20000", usecs);
    765             LOGD("Point 1 (      start): %03d.%06d:", (int)mtv1.tv_sec, (int)mtv1.tv_usec);
    766             LOGD("Point 2 (after read1): %03d.%06d:", (int)mtv2.tv_sec, (int)mtv2.tv_usec);
    767             LOGD("Point 3 (after read2): %03d.%06d:", (int)mtv3.tv_sec, (int)mtv3.tv_usec);
    768             LOGD("Point 4 (before ECNS): %03d.%06d:", (int)mtv4.tv_sec, (int)mtv4.tv_usec);
    769             LOGD("Point 5 (after  ECNS): %03d.%06d:", (int)mtv5.tv_sec, (int)mtv5.tv_usec);
    770             LOGD("Point 6 (after write): %03d.%06d:", (int)mtv6.tv_sec, (int)mtv6.tv_usec);
    771             LOGD("Point 7 (before sgnl): %03d.%06d:", (int)mtv7.tv_sec, (int)mtv7.tv_usec);
    772             LOGD("Point 8 (after unlck): %03d.%06d:", (int)mtv8.tv_sec, (int)mtv8.tv_usec);
    773         } else if ((usecs > 22000) || (usecs < 18000)) {
    774             small_jitter++;
    775             LOGD("jitter: usecs = %d should be 20000", usecs);
    776         }
    777         if ((count % 500)== 0) {
    778             LOGD("====================================== Statistics ===========================");
    779             LOGD(" After %d seconds:", count/50);
    780             LOGD(" Small jitters-  %d (%02.5f%%)", small_jitter, ((float)small_jitter)*100/count);
    781             LOGD(" Medium jitters- %d (%02.5f%%)", medium_jitter, ((float)medium_jitter)*100/count);
    782             LOGD(" Large jitters-  %d (%02.5f%%)", large_jitter, ((float)large_jitter)*100/count);
    783             LOGD("=============================================================================");
    784         }
    785 #endif
    786     }
    787 error:
    788     LOGD("%s: Exit thread loop, enabled = %d", __FUNCTION__,mProcessor->isEcnsEnabled());
    789     if (mReadBuf) {
    790         free (mReadBuf);
    791         mReadBuf = 0;
    792     }
    793     mIsRunning = false;
    794     return false;
    795 }
    796 
    797 } //namespace android
    798