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
39 extern "C" {
40 #ifdef QCOM_CSDCLIENT_ENABLED
41 static int (*csd_start_record)(int);
42 static int (*csd_stop_record)(void);
43 #endif
44
45 #ifdef QCOM_SSR_ENABLED
46 #include "surround_filters_interface.h"
47 #endif
48 }
49
50 namespace 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
64 const int chanMap[] = { 1, 2, 4, 3, 0, 5 };
65 #endif
66
AudioStreamInALSA(AudioHardwareALSA * parent,alsa_handle_t * handle,AudioSystem::audio_in_acoustics audio_acoustics)67 AudioStreamInALSA::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
~AudioStreamInALSA()116 AudioStreamInALSA::~AudioStreamInALSA()
117 {
118 close();
119 }
120
setGain(float gain)121 status_t AudioStreamInALSA::setGain(float gain)
122 {
123 return 0; //mixer() ? mixer()->setMasterGain(gain) : (status_t)NO_INIT;
124 }
125
read(void * buffer,ssize_t bytes)126 ssize_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
dump(int fd,const Vector<String16> & args)471 status_t AudioStreamInALSA::dump(int fd, const Vector<String16>& args)
472 {
473 return NO_ERROR;
474 }
475
open(int mode)476 status_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
close()485 status_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
standby()573 status_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
resetFramesLost()609 void AudioStreamInALSA::resetFramesLost()
610 {
611 mFramesLost = 0;
612 }
613
getInputFramesLost() const614 unsigned 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
setAcousticParams(void * params)623 status_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
initSurroundSoundLibrary(unsigned long buffersize)631 status_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
724 init_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
readCoeffsFromFile()765 status_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
start_csd_record(int param)866 int 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
stop_csd_record()881 int 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