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