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