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 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 73 AudioPostProcessor::~AudioPostProcessor() 74 { 75 if (mEcnsRunning) { 76 ALOGD("%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 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 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 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. 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 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 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 281 void AudioPostProcessor::stopEcns (void) 282 { 283 AutoMutex lock(mEcnsBufLock); 284 if (mEcnsRunning) { 285 ALOGD("%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 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. 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. 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 } 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 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 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 // 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 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 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