• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AudioPostProcessor()53 AudioPostProcessor::AudioPostProcessor() :
54     mEcnsScratchBuf(0), mLogNumPoints(0),  mEcnsDlBuf(0), mEcnsDlBufSize(0), mEcnsThread(0)
55 {
56     ALOGD("%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 
~AudioPostProcessor()73 AudioPostProcessor::~AudioPostProcessor()
74 {
75     if (mEcnsRunning) {
76         ALOGD("%s",__FUNCTION__);
77         enableEcns(0);
78     }
79 }
80 
convOutDevToCTO(uint32_t outDev)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 
convRateToCto(uint32_t rate)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 
configMmAudio()127 void AudioPostProcessor::configMmAudio()
128 {
129     if (mAudioMmEnvVar.accy != CTO_AUDIO_MM_ACCY_INVALID) {
130         ALOGD("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         ALOGD("CTO Audio MM processing is disabled.");
137     }
138 }
139 
enableEcns(int value)140 void AudioPostProcessor::enableEcns(int value)
141 {
142     if (mEcnsEnabled!=value) {
143         ALOGD("enableEcns() new %08x old %08x)", value, mEcnsEnabled);
144         mEcnsThread->broadcastReadCond();
145         mEcnsThread->requestExitAndWait();
146         stopEcns();
147         cleanupEcns();
148         mEcnsEnabled = value;
149     }
150 }
151 
setAudioDev(struct cpcap_audio_stream * outDev,struct cpcap_audio_stream * inDev,bool is_bt,bool is_bt_ec,bool is_spdif)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     ALOGV("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.
setPlayAudioRate(int sampRate)196 void AudioPostProcessor::setPlayAudioRate(int sampRate)
197 {
198     uint32_t rate = convRateToCto(sampRate);
199     Mutex::Autolock lock(mMmLock);
200 
201     ALOGD("AudioPostProcessor::setPlayAudioRate %d", sampRate);
202     if (rate != mAudioMmEnvVar.sample_rate) {
203         mAudioMmEnvVar.sample_rate = rate;
204         configMmAudio();
205     }
206 }
207 
doMmProcessing(void * buffer,int numSamples)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 
getEcnsRate(void)220 int AudioPostProcessor::getEcnsRate (void)
221 {
222     return mEcnsRate;
223 }
224 
initEcns(int rate,int bytes)225 void AudioPostProcessor::initEcns(int rate, int bytes)
226 {
227     ALOGD("%s",__FUNCTION__);
228     CTO_AUDIO_USECASES_CTRL mode;
229     Mutex::Autolock lock(mEcnsBufLock);
230 
231     if (rate != 8000 && rate != 16000) {
232         ALOGW("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     ALOGD("%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             ALOGE("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         ALOGE("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 
stopEcns(void)281 void AudioPostProcessor::stopEcns (void)
282 {
283     AutoMutex lock(mEcnsBufLock);
284     if (mEcnsRunning) {
285         ALOGD("%s",__FUNCTION__);
286         mEcnsRunning = 0;
287     }
288 }
289 
cleanupEcns(void)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).
writeDownlinkEcns(int fd,void * buffer,bool stereo,int bytes,Mutex * fdLock)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         ALOGV("%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             ALOGE("%s: Capture thread is stalled.", __FUNCTION__);
349         }
350         if (mEcnsOutBufSize != 0)
351             ALOGD("%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.
read(int fd,void * buffer,int bytes,int rate)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         ALOGE("Error reading from audio in: %s", strerror(errno));
369     return (int)ret;
370 }
371 
372 // Returns: Bytes processed.
applyUplinkEcns(void * buffer,int bytes,int rate)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     ALOGV("%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         ALOGE("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             //ALOGD("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             //ALOGD("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                     ALOGE("Memleak - coding error");
458                     free(mEcnsScratchBuf);
459                 }
460                 if (mEcnsOutBufSize - mEcnsOutBufReadOffset > 0) {
461                     if ((mEcnsScratchBuf=malloc(mEcnsOutBufSize - mEcnsOutBufReadOffset)) == 0) {
462                         ALOGE("%s: Alloc failed, scratch data lost.",__FUNCTION__);
463                     } else {
464                         mEcnsScratchBufSize = mEcnsOutBufSize - mEcnsOutBufReadOffset;
465                         //ALOGD("....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                 //ALOGD("Signal write thread - need data.");
476                 mEcnsBufCond.signal();
477             }
478         }
479 
480         ALOGV_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 }
ecnsLogToRam(int bytes)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             ALOGE("EC/NS AUDIO LOGGER CONFIGURATION:");
543             ALOGE("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             ALOGE("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                     ALOGE("%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                 ALOGE("EC/NS logging enabled, but memory not allocated");
577             }
578         }
579         mLogOffset += bytes;
580     }
581 }
582 
ecnsLogToFile()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                 ALOGE("Writing %d bytes to %s", mLogOffset, fname);
593                 fwrite(mLogBuf[i], mLogOffset, 1, fp);
594                 fclose(fp);
595             } else {
596                 ALOGE("Problem writing to %s", fname);
597             }
598         }
599     }
600     mLogOffset = 0;
601 }
602 
read_dock_prop(char const * path)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 	    ALOGE("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 	    ALOGE("dock property conversion error");
627 	    return -EINVAL;
628         }
629         close(fd);
630         ALOGV("buffer = %s, spkr_dock_prop = 0x%lX", buffer, spkr_dock_prop);
631         spkr_dock_prop = spkr_dock_prop ^ basic_dock_prop;
632         ALOGV("dock_prop returned = %lX", spkr_dock_prop);
633         return spkr_dock_prop;
634     } else {
635         if (already_warned == -1) {
636             ALOGE("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 //
EcnsThread()646 AudioPostProcessor::EcnsThread::EcnsThread() :
647     mReadBuf(0), mIsRunning(0)
648 {
649 }
650 
~EcnsThread()651 AudioPostProcessor::EcnsThread::~EcnsThread()
652 {
653 }
654 
readData(int fd,void * buffer,int bytes,int rate,AudioPostProcessor * pp)655 int AudioPostProcessor::EcnsThread::readData(int fd, void * buffer, int bytes, int rate,
656                                              AudioPostProcessor * pp)
657 {
658     ALOGV("%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         ALOGD("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         ALOGE("%s: ECNS thread is stalled.", __FUNCTION__);
673         mClientBuf = 0;
674         return -1;
675     }
676     return bytes;
677 }
678 
threadLoop()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     ALOGD("%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             ALOGE("%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                 ALOGE("%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             ALOGV("%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             ALOGD("jitter: usecs = %d should be 20000", usecs);
765             ALOGD("Point 1 (      start): %03d.%06d:", (int)mtv1.tv_sec, (int)mtv1.tv_usec);
766             ALOGD("Point 2 (after read1): %03d.%06d:", (int)mtv2.tv_sec, (int)mtv2.tv_usec);
767             ALOGD("Point 3 (after read2): %03d.%06d:", (int)mtv3.tv_sec, (int)mtv3.tv_usec);
768             ALOGD("Point 4 (before ECNS): %03d.%06d:", (int)mtv4.tv_sec, (int)mtv4.tv_usec);
769             ALOGD("Point 5 (after  ECNS): %03d.%06d:", (int)mtv5.tv_sec, (int)mtv5.tv_usec);
770             ALOGD("Point 6 (after write): %03d.%06d:", (int)mtv6.tv_sec, (int)mtv6.tv_usec);
771             ALOGD("Point 7 (before sgnl): %03d.%06d:", (int)mtv7.tv_sec, (int)mtv7.tv_usec);
772             ALOGD("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             ALOGD("jitter: usecs = %d should be 20000", usecs);
776         }
777         if ((count % 500)== 0) {
778             ALOGD("====================================== Statistics ===========================");
779             ALOGD(" After %d seconds:", count/50);
780             ALOGD(" Small jitters-  %d (%02.5f%%)", small_jitter, ((float)small_jitter)*100/count);
781             ALOGD(" Medium jitters- %d (%02.5f%%)", medium_jitter, ((float)medium_jitter)*100/count);
782             ALOGD(" Large jitters-  %d (%02.5f%%)", large_jitter, ((float)large_jitter)*100/count);
783             ALOGD("=============================================================================");
784         }
785 #endif
786     }
787 error:
788     ALOGD("%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