1/* AudioStreamInALSA.cpp 2 ** 3 ** Copyright 2008-2009 Wind River Systems 4 ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. 5 ** 6 ** Licensed under the Apache License, Version 2.0 (the "License"); 7 ** you may not use this file except in compliance with the License. 8 ** You may obtain a copy of the License at 9 ** 10 ** http://www.apache.org/licenses/LICENSE-2.0 11 ** 12 ** Unless required by applicable law or agreed to in writing, software 13 ** distributed under the License is distributed on an "AS IS" BASIS, 14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 ** See the License for the specific language governing permissions and 16 ** limitations under the License. 17 */ 18 19#include <errno.h> 20#include <stdarg.h> 21#include <sys/stat.h> 22#include <fcntl.h> 23#include <stdlib.h> 24#include <unistd.h> 25#include <dlfcn.h> 26 27#define LOG_TAG "AudioStreamInALSA" 28//#define LOG_NDEBUG 0 29#define LOG_NDDEBUG 0 30#include <utils/Log.h> 31#include <utils/String8.h> 32 33#include <cutils/properties.h> 34#include <media/AudioRecord.h> 35#include <hardware_legacy/power.h> 36 37#include "AudioHardwareALSA.h" 38 39extern "C" { 40#ifdef QCOM_CSDCLIENT_ENABLED 41static int (*csd_start_record)(int); 42static int (*csd_stop_record)(void); 43#endif 44 45#ifdef QCOM_SSR_ENABLED 46#include "surround_filters_interface.h" 47#endif 48} 49 50namespace android_audio_legacy 51{ 52#ifdef QCOM_SSR_ENABLED 53#define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm" 54#define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm" 55#define SURROUND_FILE_3R "/system/etc/surround_sound/filter3r.pcm" 56#define SURROUND_FILE_4R "/system/etc/surround_sound/filter4r.pcm" 57 58#define SURROUND_FILE_1I "/system/etc/surround_sound/filter1i.pcm" 59#define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm" 60#define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm" 61#define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm" 62 63// Use AAC/DTS channel mapping as default channel mapping: C,FL,FR,Ls,Rs,LFE 64const int chanMap[] = { 1, 2, 4, 3, 0, 5 }; 65#endif 66 67AudioStreamInALSA::AudioStreamInALSA(AudioHardwareALSA *parent, 68 alsa_handle_t *handle, 69 AudioSystem::audio_in_acoustics audio_acoustics) : 70 ALSAStreamOps(parent, handle), 71 mFramesLost(0), 72 mAcoustics(audio_acoustics), 73 mParent(parent) 74#ifdef QCOM_SSR_ENABLED 75 , mFp_4ch(NULL), 76 mFp_6ch(NULL), 77 mRealCoeffs(NULL), 78 mImagCoeffs(NULL), 79 mSurroundObj(NULL), 80 mSurroundOutputBuffer(NULL), 81 mSurroundInputBuffer(NULL), 82 mSurroundOutputBufferIdx(0), 83 mSurroundInputBufferIdx(0) 84#endif 85{ 86#ifdef QCOM_SSR_ENABLED 87 char c_multi_ch_dump[128] = {0}; 88 status_t err = NO_ERROR; 89 90 // Call surround sound library init if device is Surround Sound 91 if ( handle->channels == 6) { 92 if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC)) 93 || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) { 94 95 err = initSurroundSoundLibrary(handle->bufferSize); 96 if ( NO_ERROR != err) { 97 ALOGE("initSurroundSoundLibrary failed: %d handle->bufferSize:%d", err,handle->bufferSize); 98 } 99 100 property_get("ssr.pcmdump",c_multi_ch_dump,"0"); 101 if (0 == strncmp("true",c_multi_ch_dump, sizeof("ssr.dump-pcm"))) { 102 //Remember to change file system permission of data(e.g. chmod 777 data/), 103 //otherwise, fopen may fail. 104 if ( !mFp_4ch) 105 mFp_4ch = fopen("/data/4ch_ssr.pcm", "wb"); 106 if ( !mFp_6ch) 107 mFp_6ch = fopen("/data/6ch_ssr.pcm", "wb"); 108 if ((!mFp_4ch) || (!mFp_6ch)) 109 ALOGE("mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",mFp_4ch,mFp_6ch); 110 } 111 } 112 } 113#endif 114} 115 116AudioStreamInALSA::~AudioStreamInALSA() 117{ 118 close(); 119} 120 121status_t AudioStreamInALSA::setGain(float gain) 122{ 123 return 0; //mixer() ? mixer()->setMasterGain(gain) : (status_t)NO_INIT; 124} 125 126ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes) 127{ 128 int period_size; 129 130 ALOGV("read:: buffer %p, bytes %d", buffer, bytes); 131 132 int n; 133 status_t err; 134 ssize_t read = 0; 135 char *use_case; 136 int newMode = mParent->mode(); 137 138 if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) && 139 (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) && 140 (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 141 mParent->mLock.lock(); 142 snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case); 143 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) { 144 if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) && 145 (newMode == AudioSystem::MODE_IN_CALL)) { 146 ALOGD("read:: mParent->mIncallMode=%d", mParent->mIncallMode); 147 if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) && 148 (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) { 149#ifdef QCOM_CSDCLIENT_ENABLED 150 if (mParent->mFusion3Platform) { 151 mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO); 152 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, 153 sizeof(mHandle->useCase)); 154 start_csd_record(INCALL_REC_STEREO); 155 } else 156#endif 157 { 158 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL, 159 sizeof(mHandle->useCase)); 160 } 161 } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) { 162#ifdef QCOM_CSDCLIENT_ENABLED 163 if (mParent->mFusion3Platform) { 164 mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO); 165 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE, 166 sizeof(mHandle->useCase)); 167 start_csd_record(INCALL_REC_MONO); 168 } else 169#endif 170 { 171 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL, 172 sizeof(mHandle->useCase)); 173 } 174 } 175#ifdef QCOM_FM_ENABLED 176 } else if(mHandle->devices == AudioSystem::DEVICE_IN_FM_RX) { 177 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(mHandle->useCase)); 178 } else if (mHandle->devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) { 179 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(mHandle->useCase)); 180#endif 181 } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) { 182 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase)); 183 } else { 184 char value[128]; 185 property_get("persist.audio.lowlatency.rec",value,"0"); 186 if (!strcmp("true", value)) { 187 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase)); 188 } else { 189 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase)); 190 } 191 } 192 } else { 193 if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) && 194 (newMode == AudioSystem::MODE_IN_CALL)) { 195 ALOGD("read:: ---- mParent->mIncallMode=%d", mParent->mIncallMode); 196 if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) && 197 (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) { 198#ifdef QCOM_CSDCLIENT_ENABLED 199 if (mParent->mFusion3Platform) { 200 mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO); 201 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC, 202 sizeof(mHandle->useCase)); 203 start_csd_record(INCALL_REC_STEREO); 204 } else 205#endif 206 { 207 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC, 208 sizeof(mHandle->useCase)); 209 } 210 } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) { 211#ifdef QCOM_CSDCLIENT_ENABLED 212 if (mParent->mFusion3Platform) { 213 mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO); 214 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC, 215 sizeof(mHandle->useCase)); 216 start_csd_record(INCALL_REC_MONO); 217 } else 218#endif 219 { 220 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC, 221 sizeof(mHandle->useCase)); 222 } 223 } 224#ifdef QCOM_FM_ENABLED 225 } else if(mHandle->devices == AudioSystem::DEVICE_IN_FM_RX) { 226 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_FM_REC, sizeof(mHandle->useCase)); 227 } else if (mHandle->devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) { 228 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(mHandle->useCase)); 229#endif 230 } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){ 231 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(mHandle->useCase)); 232 } else { 233 char value[128]; 234 property_get("persist.audio.lowlatency.rec",value,"0"); 235 if (!strcmp("true", value)) { 236 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase)); 237 } else { 238 strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase)); 239 } 240 } 241 } 242 if (mHandle->channelMask == AUDIO_CHANNEL_IN_FRONT_BACK) { 243 mHandle->module->setFlags(mParent->mDevSettingsFlag | DMIC_FLAG); 244 } 245 free(use_case); 246 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 247 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 248#ifdef QCOM_USBAUDIO_ENABLED 249 if((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) || 250 (mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) { 251 mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AudioSystem::MODE_IN_COMMUNICATION); 252 }else 253#endif 254 { 255 mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION); 256 } 257 } else { 258#ifdef QCOM_USBAUDIO_ENABLED 259 if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)|| 260 (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){ 261 mHandle->module->route(mHandle, AudioSystem::DEVICE_IN_PROXY , mParent->mode()); 262 } else 263#endif 264 { 265 266 mHandle->module->route(mHandle, mDevices , mParent->mode()); 267 } 268 } 269 if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC) || 270 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) || 271 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_REC) || 272 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) || 273 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) || 274 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC) || 275 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_DL_REC) || 276 !strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) { 277 snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase); 278 } else { 279 snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase); 280 } 281 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 282 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 283 err = mHandle->module->startVoipCall(mHandle); 284 } 285 else 286 mHandle->module->open(mHandle); 287 if(mHandle->handle == NULL) { 288 ALOGE("read:: PCM device open failed"); 289 mParent->mLock.unlock(); 290 291 return 0; 292 } 293#ifdef QCOM_USBAUDIO_ENABLED 294 if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)|| 295 (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){ 296 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 297 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 298 mParent->musbRecordingState |= USBRECBIT_VOIPCALL; 299 } else { 300 mParent->startUsbRecordingIfNotStarted(); 301 mParent->musbRecordingState |= USBRECBIT_REC; 302 } 303 } 304#endif 305 mParent->mLock.unlock(); 306 } 307#ifdef QCOM_USBAUDIO_ENABLED 308 if(((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) || 309 (mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) && 310 (!mParent->musbRecordingState)) { 311 mParent->mLock.lock(); 312 ALOGD("Starting UsbRecording thread"); 313 mParent->startUsbRecordingIfNotStarted(); 314 if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) || 315 !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) { 316 ALOGD("Enabling voip recording bit"); 317 mParent->musbRecordingState |= USBRECBIT_VOIPCALL; 318 }else{ 319 ALOGD("Enabling HiFi Recording bit"); 320 mParent->musbRecordingState |= USBRECBIT_REC; 321 } 322 mParent->mLock.unlock(); 323 } 324#endif 325 period_size = mHandle->periodSize; 326 int read_pending = bytes; 327 328#ifdef QCOM_SSR_ENABLED 329 if (mSurroundObj) { 330 int processed = 0; 331 int processed_pending; 332 int samples = bytes >> 1; 333 void *buffer_start = buffer; 334 int period_bytes = mHandle->handle->period_size; 335 int period_samples = period_bytes >> 1; 336 337 do { 338 if (mSurroundOutputBufferIdx > 0) { 339 ALOGV("AudioStreamInALSA::read() - copy processed output " 340 "to buffer, mSurroundOutputBufferIdx = %d", 341 mSurroundOutputBufferIdx); 342 // Copy processed output to buffer 343 processed_pending = mSurroundOutputBufferIdx; 344 if (processed_pending > (samples - processed)) { 345 processed_pending = (samples - processed); 346 } 347 memcpy(buffer, mSurroundOutputBuffer, processed_pending * sizeof(Word16)); 348 buffer += processed_pending * sizeof(Word16); 349 processed += processed_pending; 350 if (mSurroundOutputBufferIdx > processed_pending) { 351 // Shift leftover samples to beginning of the buffer 352 memcpy(&mSurroundOutputBuffer[0], 353 &mSurroundOutputBuffer[processed_pending], 354 (mSurroundOutputBufferIdx - processed_pending) * sizeof(Word16)); 355 } 356 mSurroundOutputBufferIdx -= processed_pending; 357 } 358 359 if (processed >= samples) { 360 ALOGV("AudioStreamInALSA::read() - done processing buffer, " 361 "processed = %d", processed); 362 // Done processing this buffer 363 break; 364 } 365 366 // Fill input buffer until there is enough to process 367 read_pending = SSR_INPUT_FRAME_SIZE - mSurroundInputBufferIdx; 368 read = mSurroundInputBufferIdx; 369 while (mHandle->handle && read_pending > 0) { 370 n = pcm_read(mHandle->handle, &mSurroundInputBuffer[read], 371 period_bytes); 372 ALOGV("pcm_read() returned n = %d buffer:%p size:%d", n, &mSurroundInputBuffer[read], period_bytes); 373 if (n && n != -EAGAIN) { 374 //Recovery part of pcm_read. TODO:split recovery. 375 return static_cast<ssize_t>(n); 376 } 377 else if (n < 0) { 378 // Recovery is part of pcm_write. TODO split is later. 379 return static_cast<ssize_t>(n); 380 } 381 else { 382 read_pending -= period_samples; 383 read += period_samples; 384 } 385 } 386 387 388 if (mFp_4ch) { 389 fwrite( mSurroundInputBuffer, 1, 390 SSR_INPUT_FRAME_SIZE * sizeof(Word16), mFp_4ch); 391 } 392 393 //apply ssr libs to conver 4ch to 6ch 394 surround_filters_intl_process(mSurroundObj, 395 &mSurroundOutputBuffer[mSurroundOutputBufferIdx], 396 (Word16 *)mSurroundInputBuffer); 397 398 // Shift leftover samples to beginning of input buffer 399 if (read_pending < 0) { 400 memcpy(&mSurroundInputBuffer[0], 401 &mSurroundInputBuffer[SSR_INPUT_FRAME_SIZE], 402 (-read_pending) * sizeof(Word16)); 403 } 404 mSurroundInputBufferIdx = -read_pending; 405 406 if (mFp_6ch) { 407 fwrite( &mSurroundOutputBuffer[mSurroundOutputBufferIdx], 408 1, SSR_OUTPUT_FRAME_SIZE * sizeof(Word16), mFp_6ch); 409 } 410 411 mSurroundOutputBufferIdx += SSR_OUTPUT_FRAME_SIZE; 412 ALOGV("do_while loop: processed=%d, samples=%d\n", processed, samples); 413 } while (mHandle->handle && processed < samples); 414 read = processed * sizeof(Word16); 415 buffer = buffer_start; 416 } else 417#endif 418 { 419 420 do { 421 if (read_pending < period_size) { 422 read_pending = period_size; 423 } 424 425 n = pcm_read(mHandle->handle, buffer, 426 period_size); 427 ALOGV("pcm_read() returned n = %d", n); 428 if (n && (n == -EIO || n == -EAGAIN || n == -EPIPE || n == -EBADFD)) { 429 mParent->mLock.lock(); 430 ALOGW("pcm_read() returned error n %d, Recovering from error\n", n); 431 pcm_close(mHandle->handle); 432 mHandle->handle = NULL; 433 if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) || 434 (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) { 435 pcm_close(mHandle->rxHandle); 436 mHandle->rxHandle = NULL; 437 mHandle->module->startVoipCall(mHandle); 438 } 439 else 440 mHandle->module->open(mHandle); 441 442 if(mHandle->handle == NULL) { 443 ALOGE("read:: PCM device re-open failed"); 444 mParent->mLock.unlock(); 445 return 0; 446 } 447 448 mParent->mLock.unlock(); 449 continue; 450 } 451 else if (n < 0) { 452 ALOGD("pcm_read() returned n < 0"); 453 return static_cast<ssize_t>(n); 454 } 455 else { 456 read += static_cast<ssize_t>((period_size)); 457 read_pending -= period_size; 458 //Set mute by cleanning buffers read 459 if (mParent->mMicMute) { 460 memset(buffer, 0, period_size); 461 } 462 buffer = ((uint8_t *)buffer) + period_size; 463 } 464 465 } while (mHandle->handle && read < bytes); 466 } 467 468 return read; 469} 470 471status_t AudioStreamInALSA::dump(int fd, const Vector<String16>& args) 472{ 473 return NO_ERROR; 474} 475 476status_t AudioStreamInALSA::open(int mode) 477{ 478 Mutex::Autolock autoLock(mParent->mLock); 479 480 status_t status = ALSAStreamOps::open(mode); 481 482 return status; 483} 484 485status_t AudioStreamInALSA::close() 486{ 487 Mutex::Autolock autoLock(mParent->mLock); 488 489 ALOGD("close"); 490 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 491 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 492 if((mParent->mVoipStreamCount)) { 493#ifdef QCOM_USBAUDIO_ENABLED 494 ALOGD("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState, 495 mParent->mVoipStreamCount ); 496 if(mParent->mVoipStreamCount == 1) { 497 ALOGD("Deregistering VOIP Call bit, musbPlaybackState:%d," 498 "musbRecordingState:%d", mParent->musbPlaybackState, mParent->musbRecordingState); 499 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL; 500 mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL; 501 mParent->closeUsbRecordingIfNothingActive(); 502 mParent->closeUsbPlaybackIfNothingActive(); 503 } 504#endif 505 return NO_ERROR; 506 } 507 mParent->mVoipStreamCount = 0; 508#ifdef QCOM_USBAUDIO_ENABLED 509 } else { 510 ALOGD("Deregistering REC bit, musbRecordingState:%d", mParent->musbRecordingState); 511 mParent->musbRecordingState &= ~USBRECBIT_REC; 512#endif 513 } 514#ifdef QCOM_CSDCLIENT_ENABLED 515 if (mParent->mFusion3Platform) { 516 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) || 517 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE))) { 518 stop_csd_record(); 519 } 520 } 521#endif 522 ALOGD("close"); 523#ifdef QCOM_USBAUDIO_ENABLED 524 mParent->closeUsbRecordingIfNothingActive(); 525#endif 526 527 ALSAStreamOps::close(); 528 529#ifdef QCOM_SSR_ENABLED 530 if (mSurroundObj) { 531 surround_filters_release(mSurroundObj); 532 if (mSurroundObj) 533 free(mSurroundObj); 534 mSurroundObj = NULL; 535 if (mRealCoeffs){ 536 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) { 537 if (mRealCoeffs[i]) { 538 free(mRealCoeffs[i]); 539 mRealCoeffs[i] = NULL; 540 } 541 } 542 free(mRealCoeffs); 543 mRealCoeffs = NULL; 544 } 545 if (mImagCoeffs){ 546 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) { 547 if (mImagCoeffs[i]) { 548 free(mImagCoeffs[i]); 549 mImagCoeffs[i] = NULL; 550 } 551 } 552 free(mImagCoeffs); 553 mImagCoeffs = NULL; 554 } 555 if (mSurroundOutputBuffer){ 556 free(mSurroundOutputBuffer); 557 mSurroundOutputBuffer = NULL; 558 } 559 if (mSurroundInputBuffer) { 560 free(mSurroundInputBuffer); 561 mSurroundInputBuffer = NULL; 562 } 563 564 if ( mFp_4ch ) fclose(mFp_4ch); 565 if ( mFp_6ch ) fclose(mFp_6ch); 566 567 } 568#endif 569 570 return NO_ERROR; 571} 572 573status_t AudioStreamInALSA::standby() 574{ 575 Mutex::Autolock autoLock(mParent->mLock); 576 577 ALOGD("standby"); 578 579 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) || 580 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) { 581 return NO_ERROR; 582 } 583 584#ifdef QCOM_CSDCLIENT_ENABLED 585 ALOGD("standby"); 586 if (mParent->mFusion3Platform) { 587 if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_INCALL_REC)) || 588 (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE))) { 589 ALOGD(" into standby, stop record"); 590 stop_csd_record(); 591 } 592 } 593#endif 594 mHandle->module->standby(mHandle); 595 596#ifdef QCOM_USBAUDIO_ENABLED 597 ALOGD("Checking for musbRecordingState %d", mParent->musbRecordingState); 598 mParent->musbRecordingState &= ~USBRECBIT_REC; 599 mParent->closeUsbRecordingIfNothingActive(); 600#endif 601 602 if (mHandle->channelMask == AUDIO_CHANNEL_IN_FRONT_BACK) { 603 mHandle->module->setFlags(mParent->mDevSettingsFlag); 604 } 605 606 return NO_ERROR; 607} 608 609void AudioStreamInALSA::resetFramesLost() 610{ 611 mFramesLost = 0; 612} 613 614unsigned int AudioStreamInALSA::getInputFramesLost() const 615{ 616 unsigned int count = mFramesLost; 617 // Stupid interface wants us to have a side effect of clearing the count 618 // but is defined as a const to prevent such a thing. 619 ((AudioStreamInALSA *)this)->resetFramesLost(); 620 return count; 621} 622 623status_t AudioStreamInALSA::setAcousticParams(void *params) 624{ 625 Mutex::Autolock autoLock(mParent->mLock); 626 627 return (status_t)NO_ERROR; 628} 629 630#ifdef QCOM_SSR_ENABLED 631status_t AudioStreamInALSA::initSurroundSoundLibrary(unsigned long buffersize) 632{ 633 int subwoofer = 0; // subwoofer channel assignment: default as first microphone input channel 634 int low_freq = 4; // frequency upper bound for subwoofer: frequency=(low_freq-1)/FFT_SIZE*samplingRate, default as 4 635 int high_freq = 100; // frequency upper bound for spatial processing: frequency=(high_freq-1)/FFT_SIZE*samplingRate, default as 100 636 int ret = 0; 637 638 mSurroundInputBufferIdx = 0; 639 mSurroundOutputBufferIdx = 0; 640 641 if ( mSurroundObj ) { 642 ALOGE("ola filter library is already initialized"); 643 return ALREADY_EXISTS; 644 } 645 646 // Allocate memory for input buffer 647 mSurroundInputBuffer = (Word16 *) calloc(2 * SSR_INPUT_FRAME_SIZE, 648 sizeof(Word16)); 649 if ( !mSurroundInputBuffer ) { 650 ALOGE("Memory allocation failure. Not able to allocate memory for surroundInputBuffer"); 651 goto init_fail; 652 } 653 654 // Allocate memory for output buffer 655 mSurroundOutputBuffer = (Word16 *) calloc(2 * SSR_OUTPUT_FRAME_SIZE, 656 sizeof(Word16)); 657 if ( !mSurroundOutputBuffer ) { 658 ALOGE("Memory allocation failure. Not able to allocate memory for surroundOutputBuffer"); 659 goto init_fail; 660 } 661 662 // Allocate memory for real and imag coeffs array 663 mRealCoeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *)); 664 if ( !mRealCoeffs ) { 665 ALOGE("Memory allocation failure during real Coefficient array"); 666 goto init_fail; 667 } 668 669 mImagCoeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *)); 670 if ( !mImagCoeffs ) { 671 ALOGE("Memory allocation failure during imaginary Coefficient array"); 672 goto init_fail; 673 } 674 675 if( readCoeffsFromFile() != NO_ERROR) { 676 ALOGE("Error while loading coeffs from file"); 677 goto init_fail; 678 } 679 680 //calculate the size of data to allocate for mSurroundObj 681 ret = surround_filters_init(NULL, 682 6, // Num output channel 683 4, // Num input channel 684 mRealCoeffs, // Coeffs hardcoded in header 685 mImagCoeffs, // Coeffs hardcoded in header 686 subwoofer, 687 low_freq, 688 high_freq, 689 NULL); 690 691 if ( ret > 0 ) { 692 ALOGV("Allocating surroundObj size is %d", ret); 693 mSurroundObj = (void *)malloc(ret); 694 memset(mSurroundObj,0,ret); 695 if (NULL != mSurroundObj) { 696 //initialize after allocating the memory for mSurroundObj 697 ret = surround_filters_init(mSurroundObj, 698 6, 699 4, 700 mRealCoeffs, 701 mImagCoeffs, 702 subwoofer, 703 low_freq, 704 high_freq, 705 NULL); 706 if (0 != ret) { 707 ALOGE("surround_filters_init failed with ret:%d",ret); 708 surround_filters_release(mSurroundObj); 709 goto init_fail; 710 } 711 } else { 712 ALOGE("Allocationg mSurroundObj failed"); 713 goto init_fail; 714 } 715 } else { 716 ALOGE("surround_filters_init(mSurroundObj=Null) failed with ret: %d",ret); 717 goto init_fail; 718 } 719 720 (void) surround_filters_set_channel_map(mSurroundObj, chanMap); 721 722 return NO_ERROR; 723 724init_fail: 725 if (mSurroundObj) { 726 free(mSurroundObj); 727 mSurroundObj = NULL; 728 } 729 if (mSurroundOutputBuffer) { 730 free(mSurroundOutputBuffer); 731 mSurroundOutputBuffer = NULL; 732 } 733 if (mSurroundInputBuffer) { 734 free(mSurroundInputBuffer); 735 mSurroundInputBuffer = NULL; 736 } 737 if (mRealCoeffs){ 738 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) { 739 if (mRealCoeffs[i]) { 740 free(mRealCoeffs[i]); 741 mRealCoeffs[i] = NULL; 742 } 743 } 744 free(mRealCoeffs); 745 mRealCoeffs = NULL; 746 } 747 if (mImagCoeffs){ 748 for (int i =0; i<COEFF_ARRAY_SIZE; i++ ) { 749 if (mImagCoeffs[i]) { 750 free(mImagCoeffs[i]); 751 mImagCoeffs[i] = NULL; 752 } 753 } 754 free(mImagCoeffs); 755 mImagCoeffs = NULL; 756 } 757 758 return NO_MEMORY; 759 760} 761 762 763// Helper function to read coeffs from File and updates real and imaginary 764// coeff array member variable 765status_t AudioStreamInALSA::readCoeffsFromFile() 766{ 767 FILE *flt1r; 768 FILE *flt2r; 769 FILE *flt3r; 770 FILE *flt4r; 771 FILE *flt1i; 772 FILE *flt2i; 773 FILE *flt3i; 774 FILE *flt4i; 775 776 if ( (flt1r = fopen(SURROUND_FILE_1R, "rb")) == NULL ) { 777 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_1R); 778 return NAME_NOT_FOUND; 779 } 780 781 if ( (flt2r = fopen(SURROUND_FILE_2R, "rb")) == NULL ) { 782 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_2R); 783 return NAME_NOT_FOUND; 784 } 785 786 if ( (flt3r = fopen(SURROUND_FILE_3R, "rb")) == NULL ) { 787 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_3R); 788 return NAME_NOT_FOUND; 789 } 790 791 if ( (flt4r = fopen(SURROUND_FILE_4R, "rb")) == NULL ) { 792 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_4R); 793 return NAME_NOT_FOUND; 794 } 795 796 if ( (flt1i = fopen(SURROUND_FILE_1I, "rb")) == NULL ) { 797 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_1I); 798 return NAME_NOT_FOUND; 799 } 800 801 if ( (flt2i = fopen(SURROUND_FILE_2I, "rb")) == NULL ) { 802 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_2I); 803 return NAME_NOT_FOUND; 804 } 805 806 if ( (flt3i = fopen(SURROUND_FILE_3I, "rb")) == NULL ) { 807 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_3I); 808 return NAME_NOT_FOUND; 809 } 810 811 if ( (flt4i = fopen(SURROUND_FILE_4I, "rb")) == NULL ) { 812 ALOGE("Cannot open filter co-efficient file %s", SURROUND_FILE_4I); 813 return NAME_NOT_FOUND; 814 } 815 ALOGV("readCoeffsFromFile all filter files opened"); 816 817 for (int i=0; i<COEFF_ARRAY_SIZE; i++) { 818 mRealCoeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16)); 819 } 820 for (int i=0; i<COEFF_ARRAY_SIZE; i++) { 821 mImagCoeffs[i] = (Word16 *)calloc(FILT_SIZE, sizeof(Word16)); 822 } 823 824 // Read real co-efficients 825 if (NULL != mRealCoeffs[0]) { 826 fread(mRealCoeffs[0], sizeof(int16), FILT_SIZE, flt1r); 827 } 828 if (NULL != mRealCoeffs[0]) { 829 fread(mRealCoeffs[1], sizeof(int16), FILT_SIZE, flt2r); 830 } 831 if (NULL != mRealCoeffs[0]) { 832 fread(mRealCoeffs[2], sizeof(int16), FILT_SIZE, flt3r); 833 } 834 if (NULL != mRealCoeffs[0]) { 835 fread(mRealCoeffs[3], sizeof(int16), FILT_SIZE, flt4r); 836 } 837 838 // read imaginary co-efficients 839 if (NULL != mImagCoeffs[0]) { 840 fread(mImagCoeffs[0], sizeof(int16), FILT_SIZE, flt1i); 841 } 842 if (NULL != mImagCoeffs[0]) { 843 fread(mImagCoeffs[1], sizeof(int16), FILT_SIZE, flt2i); 844 } 845 if (NULL != mImagCoeffs[0]) { 846 fread(mImagCoeffs[2], sizeof(int16), FILT_SIZE, flt3i); 847 } 848 if (NULL != mImagCoeffs[0]) { 849 fread(mImagCoeffs[3], sizeof(int16), FILT_SIZE, flt4i); 850 } 851 852 fclose(flt1r); 853 fclose(flt2r); 854 fclose(flt3r); 855 fclose(flt4r); 856 fclose(flt1i); 857 fclose(flt2i); 858 fclose(flt3i); 859 fclose(flt4i); 860 861 return NO_ERROR; 862} 863#endif 864 865#ifdef QCOM_CSDCLIENT_ENABLED 866int AudioStreamInALSA::start_csd_record(int param) 867{ 868 int err = NO_ERROR; 869 870 if (mParent->mCsdHandle != NULL) { 871 csd_start_record = (int (*)(int))::dlsym(mParent->mCsdHandle,"csd_client_start_record"); 872 if (csd_start_record == NULL) { 873 ALOGE("dlsym:Error:%s Loading csd_client_start_record", dlerror()); 874 } else { 875 err = csd_start_record(param); 876 } 877 } 878 return err; 879} 880 881int AudioStreamInALSA::stop_csd_record() 882{ 883 int err = NO_ERROR; 884 if (mParent->mCsdHandle != NULL) { 885 csd_stop_record = (int (*)())::dlsym(mParent->mCsdHandle,"csd_client_stop_record"); 886 if (csd_start_record == NULL) { 887 ALOGE("dlsym:Error:%s Loading csd_client_start_record", dlerror()); 888 } else { 889 csd_stop_record(); 890 } 891 } 892 return err; 893} 894#endif 895 896} // namespace android_audio_legacy 897