1/* alsa_default.cpp
2 **
3 ** Copyright 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#define LOG_TAG "ALSAModule"
20//#define LOG_NDEBUG 0
21#define LOG_NDDEBUG 0
22#include <utils/Log.h>
23#include <cutils/properties.h>
24#include <linux/ioctl.h>
25#include "AudioUtil.h"
26#include "AudioHardwareALSA.h"
27#include <media/AudioRecord.h>
28#include <dlfcn.h>
29#ifdef QCOM_CSDCLIENT_ENABLED
30extern "C" {
31static int (*csd_disable_device)();
32static int (*csd_enable_device)(int, int, uint32_t);
33static int (*csd_volume)(int);
34static int (*csd_mic_mute)(int);
35static int (*csd_wide_voice)(uint8_t);
36static int (*csd_slow_talk)(uint8_t);
37static int (*csd_fens)(uint8_t);
38static int (*csd_start_voice)();
39static int (*csd_stop_voice)();
40}
41#endif
42
43#ifndef ALSA_DEFAULT_SAMPLE_RATE
44#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
45#endif
46
47#define BTSCO_RATE_16KHZ 16000
48#define USECASE_TYPE_RX 1
49#define USECASE_TYPE_TX 2
50#define MAX_HDMI_CHANNEL_CNT 6
51
52namespace android_audio_legacy
53{
54
55static int      s_device_open(const hw_module_t*, const char*, hw_device_t**);
56static int      s_device_close(hw_device_t*);
57static status_t s_init(alsa_device_t *, ALSAHandleList &);
58static status_t s_open(alsa_handle_t *);
59static status_t s_close(alsa_handle_t *);
60static status_t s_standby(alsa_handle_t *);
61static status_t s_route(alsa_handle_t *, uint32_t, int);
62static status_t s_start_voice_call(alsa_handle_t *);
63static status_t s_start_voip_call(alsa_handle_t *);
64static status_t s_start_fm(alsa_handle_t *);
65static void     s_set_voice_volume(int);
66static void     s_set_voip_volume(int);
67static void     s_set_mic_mute(int);
68static void     s_set_voip_mic_mute(int);
69static void     s_set_voip_config(int, int);
70static status_t s_set_fm_vol(int);
71static void     s_set_btsco_rate(int);
72static status_t s_set_lpa_vol(int);
73static void     s_enable_wide_voice(bool flag);
74static void     s_enable_fens(bool flag);
75static void     s_set_flags(uint32_t flags);
76static status_t s_set_compressed_vol(int);
77static void     s_enable_slow_talk(bool flag);
78static void     s_set_voc_rec_mode(uint8_t mode);
79static void     s_set_volte_mic_mute(int state);
80static void     s_set_volte_volume(int vol);
81static bool     s_is_tmus();
82#ifdef SEPERATED_AUDIO_INPUT
83static void     s_setInput(int);
84
85static int input_source;
86#endif
87static int mccmnc;
88#ifdef QCOM_CSDCLIENT_ENABLED
89static void     s_set_csd_handle(void*);
90#endif
91
92static char mic_type[25];
93static char curRxUCMDevice[50];
94static char curTxUCMDevice[50];
95static int fluence_mode;
96static int fmVolume;
97#ifdef USES_FLUENCE_INCALL
98static uint32_t mDevSettingsFlag = TTY_OFF | DMIC_FLAG;
99#else
100static uint32_t mDevSettingsFlag = TTY_OFF;
101#endif
102static int btsco_samplerate = 8000;
103static ALSAUseCaseList mUseCaseList;
104static void *csd_handle;
105
106static hw_module_methods_t s_module_methods = {
107    open            : s_device_open
108};
109
110extern "C" {
111hw_module_t HAL_MODULE_INFO_SYM = {
112    tag             : HARDWARE_MODULE_TAG,
113    version_major   : 1,
114    version_minor   : 0,
115    id              : ALSA_HARDWARE_MODULE_ID,
116    name            : "QCOM ALSA module",
117    author          : "QuIC Inc",
118    methods         : &s_module_methods,
119    dso             : 0,
120    reserved        : {0,},
121};
122}
123
124static int s_device_open(const hw_module_t* module, const char* name,
125        hw_device_t** device)
126{
127    char value[128];
128    alsa_device_t *dev;
129    dev = (alsa_device_t *) malloc(sizeof(*dev));
130    if (!dev) return -ENOMEM;
131
132    memset(dev, 0, sizeof(*dev));
133
134    /* initialize the procs */
135    dev->common.tag = HARDWARE_DEVICE_TAG;
136    dev->common.version = 0;
137    dev->common.module = (hw_module_t *) module;
138    dev->common.close = s_device_close;
139    dev->init = s_init;
140    dev->open = s_open;
141    dev->close = s_close;
142    dev->route = s_route;
143    dev->standby = s_standby;
144    dev->startVoiceCall = s_start_voice_call;
145    dev->startVoipCall = s_start_voip_call;
146    dev->startFm = s_start_fm;
147    dev->setVoiceVolume = s_set_voice_volume;
148    dev->setVoipVolume = s_set_voip_volume;
149    dev->setMicMute = s_set_mic_mute;
150    dev->setVoipMicMute = s_set_voip_mic_mute;
151    dev->setVoipConfig = s_set_voip_config;
152    dev->setFmVolume = s_set_fm_vol;
153    dev->setBtscoRate = s_set_btsco_rate;
154    dev->setLpaVolume = s_set_lpa_vol;
155    dev->enableWideVoice = s_enable_wide_voice;
156    dev->enableFENS = s_enable_fens;
157    dev->setFlags = s_set_flags;
158    dev->setCompressedVolume = s_set_compressed_vol;
159    dev->enableSlowTalk = s_enable_slow_talk;
160    dev->setVocRecMode = s_set_voc_rec_mode;
161    dev->setVoLTEMicMute = s_set_volte_mic_mute;
162    dev->setVoLTEVolume = s_set_volte_volume;
163#ifdef SEPERATED_AUDIO_INPUT
164    dev->setInput = s_setInput;
165#endif
166#ifdef QCOM_CSDCLIENT_ENABLED
167    dev->setCsdHandle = s_set_csd_handle;
168#endif
169    *device = &dev->common;
170
171    property_get("persist.audio.handset.mic",value,"0");
172    strlcpy(mic_type, value, sizeof(mic_type));
173    property_get("persist.audio.fluence.mode",value,"0");
174    if (!strcmp("broadside", value)) {
175        fluence_mode = FLUENCE_MODE_BROADSIDE;
176    } else {
177        fluence_mode = FLUENCE_MODE_ENDFIRE;
178    }
179    strlcpy(curRxUCMDevice, "None", sizeof(curRxUCMDevice));
180    strlcpy(curTxUCMDevice, "None", sizeof(curTxUCMDevice));
181    ALOGV("ALSA module opened");
182
183    return 0;
184}
185
186static int s_device_close(hw_device_t* device)
187{
188    free(device);
189    device = NULL;
190    return 0;
191}
192
193// ----------------------------------------------------------------------------
194
195static const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE;
196
197static void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode);
198static char *getUCMDevice(uint32_t devices, int input, char *rxDevice);
199static void disableDevice(alsa_handle_t *handle);
200int getUseCaseType(const char *useCase);
201
202static int callMode = AudioSystem::MODE_NORMAL;
203// ----------------------------------------------------------------------------
204
205bool platform_is_Fusion3()
206{
207    char platform[128], baseband[128];
208    property_get("ro.board.platform", platform, "");
209    property_get("ro.baseband", baseband, "");
210    if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband))
211        return true;
212    else
213        return false;
214}
215
216int deviceName(alsa_handle_t *handle, unsigned flags, char **value)
217{
218    int ret = 0;
219    char ident[70];
220
221    if (flags & PCM_IN) {
222        strlcpy(ident, "CapturePCM/", sizeof(ident));
223    } else {
224        strlcpy(ident, "PlaybackPCM/", sizeof(ident));
225    }
226    strlcat(ident, handle->useCase, sizeof(ident));
227    ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value);
228    ALOGD("Device value returned is %s", (*value));
229    return ret;
230}
231
232status_t setHDMIChannelCount()
233{
234    status_t err = NO_ERROR;
235    int channel_count = 0;
236    const char *channel_cnt_str = NULL;
237    EDID_AUDIO_INFO info = { 0 };
238
239    ALSAControl control("/dev/snd/controlC0");
240    if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
241        for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
242            if (info.AudioBlocksArray[i].nChannels > channel_count &&
243                  info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) {
244                channel_count = info.AudioBlocksArray[i].nChannels;
245            }
246        }
247    }
248
249    switch (channel_count) {
250    case 6: channel_cnt_str = "Six"; break;
251    case 5: channel_cnt_str = "Five"; break;
252    case 4: channel_cnt_str = "Four"; break;
253    case 3: channel_cnt_str = "Three"; break;
254    default: channel_cnt_str = "Two"; break;
255    }
256    ALOGD("HDMI channel count: %s", channel_cnt_str);
257    control.set("HDMI_RX Channels", channel_cnt_str);
258
259    return err;
260}
261
262status_t setHardwareParams(alsa_handle_t *handle)
263{
264    struct snd_pcm_hw_params *params;
265    unsigned long bufferSize, reqBuffSize;
266    unsigned int periodTime, bufferTime;
267    unsigned int requestedRate = handle->sampleRate;
268    int status = 0;
269    int channels = handle->channels;
270    snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE;
271
272    params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
273    if (!params) {
274        ALOGE("Failed to allocate ALSA hardware parameters!");
275        return NO_INIT;
276    }
277
278    reqBuffSize = handle->bufferSize;
279    ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d",
280         (int) reqBuffSize, handle->channels, handle->sampleRate);
281
282#ifdef QCOM_SSR_ENABLED
283    if (channels == 6) {
284        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
285            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
286            ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
287            channels = 4;
288        }
289    }
290#endif
291
292    param_init(params);
293    param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
294                   SNDRV_PCM_ACCESS_RW_INTERLEAVED);
295    if (handle->format != SNDRV_PCM_FORMAT_S16_LE) {
296        if (handle->format == AudioSystem::AMR_NB
297            || handle->format == AudioSystem::AMR_WB
298#ifdef QCOM_QCHAT_ENABLED
299            || handle->format == AudioSystem::EVRC
300            || handle->format == AudioSystem::EVRCB
301            || handle->format == AudioSystem::EVRCWB
302#endif
303            )
304              format = SNDRV_PCM_FORMAT_SPECIAL;
305    }
306    param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
307                   format);
308    param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
309                   SNDRV_PCM_SUBFORMAT_STD);
310    param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
311    param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
312    param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
313                   channels * 16);
314    param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
315                  channels);
316    param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate);
317    param_set_hw_refine(handle->handle, params);
318
319    if (param_set_hw_params(handle->handle, params)) {
320        ALOGE("cannot set hw params");
321        return NO_INIT;
322    }
323    param_dump(params);
324
325    handle->handle->buffer_size = pcm_buffer_size(params);
326    handle->handle->period_size = pcm_period_size(params);
327    handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size;
328    ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d",
329        handle->handle->buffer_size, handle->handle->period_size,
330        handle->handle->period_cnt);
331    handle->handle->rate = handle->sampleRate;
332    handle->handle->channels = handle->channels;
333    handle->periodSize = handle->handle->period_size;
334    if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) &&
335        strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) &&
336        (6 != handle->channels)) {
337        //Do not update buffersize for 5.1 recording
338        handle->bufferSize = handle->handle->period_size;
339    }
340
341    return NO_ERROR;
342}
343
344status_t setSoftwareParams(alsa_handle_t *handle)
345{
346    struct snd_pcm_sw_params* params;
347    struct pcm* pcm = handle->handle;
348
349    unsigned long periodSize = pcm->period_size;
350    int channels = handle->channels;
351
352    params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
353    if (!params) {
354        LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
355        return NO_INIT;
356    }
357
358#ifdef QCOM_SSR_ENABLED
359    if (channels == 6) {
360        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
361            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
362            ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
363            channels = 4;
364        }
365    }
366#endif
367
368    // Get the current software parameters
369    params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
370    params->period_step = 1;
371    if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
372        (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){
373          ALOGV("setparam:  start & stop threshold for Voip ");
374          params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2;
375          params->start_threshold = periodSize/2;
376          params->stop_threshold = INT_MAX;
377     } else {
378         params->avail_min = periodSize/(channels * 2);
379         params->start_threshold = periodSize/(channels * 2);
380         params->stop_threshold = INT_MAX;
381     }
382    params->silence_threshold = 0;
383    params->silence_size = 0;
384
385    if (param_set_sw_params(handle->handle, params)) {
386        ALOGE("cannot set sw params");
387        return NO_INIT;
388    }
389    return NO_ERROR;
390}
391
392void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode)
393{
394    const char **mods_list;
395    use_case_t useCaseNode;
396    unsigned usecase_type = 0;
397    bool inCallDevSwitch = false;
398    char *rxDevice, *txDevice, ident[70], *use_case = NULL;
399    int err = 0, index, mods_size;
400    int rx_dev_id, tx_dev_id;
401    ALOGD("%s: device %d mode:%d", __FUNCTION__, devices, mode);
402
403    if ((mode == AudioSystem::MODE_IN_CALL)  || (mode == AudioSystem::MODE_IN_COMMUNICATION)) {
404        if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
405            (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
406            devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET |
407                      AudioSystem::DEVICE_IN_WIRED_HEADSET);
408        } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
409            devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
410                      AudioSystem::DEVICE_IN_BUILTIN_MIC);
411        } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
412            if (mode == AudioSystem::MODE_IN_CALL) {
413                devices |= AudioSystem::DEVICE_OUT_EARPIECE;
414            } else if (mode == AudioSystem::MODE_IN_COMMUNICATION) {
415                if (!strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, MAX_LEN(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER))) {
416                    devices &= ~AudioSystem::DEVICE_IN_BUILTIN_MIC;
417                    devices |= AudioSystem::DEVICE_IN_BACK_MIC;
418                }
419            }
420        } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
421            devices = devices | AudioSystem::DEVICE_IN_BUILTIN_MIC;
422        } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
423            devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC |
424                       AudioSystem::DEVICE_OUT_SPEAKER);
425        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
426                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
427                   (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
428            devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET |
429                      AudioSystem::DEVICE_OUT_BLUETOOTH_SCO);
430#ifdef QCOM_ANC_HEADSET_ENABLED
431        } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
432                   (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) {
433            devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET |
434                      AudioSystem::DEVICE_IN_ANC_HEADSET);
435        } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
436            devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE |
437                      AudioSystem::DEVICE_IN_BUILTIN_MIC);
438#endif
439        } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
440            if (mode == AudioSystem::MODE_IN_CALL)
441                devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC |
442                           AudioSystem::DEVICE_OUT_SPEAKER);
443            else
444                devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL |
445                          AudioSystem::DEVICE_IN_BACK_MIC);
446#ifdef QCOM_PROXY_DEVICE_ENABLED
447        } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) ||
448                  (devices & AudioSystem::DEVICE_IN_PROXY)) {
449            devices = devices | (AudioSystem::DEVICE_OUT_PROXY |
450                      AudioSystem::DEVICE_IN_PROXY);
451#endif
452        }
453    }
454#ifdef QCOM_SSR_ENABLED
455    if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) {
456        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
457            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
458            ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase);
459            s_set_flags(SSRQMIC_FLAG);
460        }
461    }
462#endif
463
464    rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL);
465    txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice);
466
467    if ((rxDevice != NULL) && (txDevice != NULL)) {
468        if (((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) ||
469            (strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN))) &&
470            ((mode == AudioSystem::MODE_IN_CALL)  ||
471            (mode == AudioSystem::MODE_IN_COMMUNICATION)))
472            inCallDevSwitch = true;
473    }
474
475#ifdef QCOM_CSDCLIENT_ENABLED
476    if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
477        if (csd_disable_device == NULL) {
478            ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
479        } else {
480            err = csd_disable_device();
481            if (err < 0)
482            {
483                ALOGE("csd_client_disable_device, failed, error %d", err);
484            }
485        }
486    }
487#endif
488
489    snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case);
490    mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
491    if (rxDevice != NULL) {
492        if ((strncmp(curRxUCMDevice, "None", 4)) &&
493            ((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
494            if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
495                strlen(SND_USE_CASE_VERB_INACTIVE)))) {
496                usecase_type = getUseCaseType(use_case);
497                if (usecase_type & USECASE_TYPE_RX) {
498                    ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
499                    strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
500                    snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
501                    mUseCaseList.push_front(useCaseNode);
502                }
503            }
504            if (mods_size) {
505                for(index = 0; index < mods_size; index++) {
506                    usecase_type = getUseCaseType(mods_list[index]);
507                    if (usecase_type & USECASE_TYPE_RX) {
508                        ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
509                        strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
510                        snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
511                        mUseCaseList.push_back(useCaseNode);
512                    }
513                }
514            }
515            snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice);
516        }
517    }
518    if (txDevice != NULL) {
519        if ((strncmp(curTxUCMDevice, "None", 4)) &&
520            ((strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
521            if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
522                strlen(SND_USE_CASE_VERB_INACTIVE)))) {
523                usecase_type = getUseCaseType(use_case);
524                if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
525                    ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
526                    strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
527                    snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
528                    mUseCaseList.push_front(useCaseNode);
529                }
530            }
531            if (mods_size) {
532                for(index = 0; index < mods_size; index++) {
533                    usecase_type = getUseCaseType(mods_list[index]);
534                    if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
535                        ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
536                        strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
537                        snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
538                        mUseCaseList.push_back(useCaseNode);
539                    }
540                }
541            }
542            snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice);
543       }
544    }
545    ALOGD("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, curRxUCMDevice, curTxUCMDevice);
546
547    if (rxDevice != NULL) {
548        snd_use_case_set(handle->ucMgr, "_enadev", rxDevice);
549        strlcpy(curRxUCMDevice, rxDevice, sizeof(curRxUCMDevice));
550#ifdef QCOM_FM_ENABLED
551        if (devices & AudioSystem::DEVICE_OUT_FM)
552            s_set_fm_vol(fmVolume);
553#endif
554    }
555    if (txDevice != NULL) {
556       snd_use_case_set(handle->ucMgr, "_enadev", txDevice);
557       strlcpy(curTxUCMDevice, txDevice, sizeof(curTxUCMDevice));
558    }
559    for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) {
560        ALOGD("Route use case %s\n", it->useCase);
561        if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
562            strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) {
563            snd_use_case_set(handle->ucMgr, "_verb", it->useCase);
564        } else {
565            snd_use_case_set(handle->ucMgr, "_enamod", it->useCase);
566        }
567    }
568    if (!mUseCaseList.empty())
569        mUseCaseList.clear();
570    if (use_case != NULL) {
571        free(use_case);
572        use_case = NULL;
573    }
574    ALOGD("switchDevice: curTxUCMDevivce %s curRxDevDevice %s", curTxUCMDevice, curRxUCMDevice);
575
576    if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
577        /* get tx acdb id */
578        memset(&ident,0,sizeof(ident));
579        strlcpy(ident, "ACDBID/", sizeof(ident));
580        strlcat(ident, curTxUCMDevice, sizeof(ident));
581        tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
582
583       /* get rx acdb id */
584        memset(&ident,0,sizeof(ident));
585        strlcpy(ident, "ACDBID/", sizeof(ident));
586        strlcat(ident, curRxUCMDevice, sizeof(ident));
587        rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
588
589        if (((rx_dev_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID ) || (rx_dev_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID ))
590         && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
591            tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
592        }
593
594#ifdef QCOM_CSDCLIENT_ENABLED
595        ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
596        if (csd_enable_device == NULL) {
597            ALOGE("dlsym:Error:%s Loading csd_client_enable_device", dlerror());
598        } else {
599            err = csd_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag);
600            if (err < 0)
601            {
602                ALOGE("csd_client_disable_device failed, error %d", err);
603            }
604        }
605#endif
606    }
607
608    if (rxDevice != NULL) {
609        free(rxDevice);
610        rxDevice = NULL;
611    }
612    if (txDevice != NULL) {
613        free(txDevice);
614        txDevice = NULL;
615    }
616}
617
618// ----------------------------------------------------------------------------
619
620static status_t s_init(alsa_device_t *module, ALSAHandleList &list)
621{
622    ALOGV("s_init: Initializing devices for ALSA module");
623
624    list.clear();
625
626    return NO_ERROR;
627}
628
629static status_t s_open(alsa_handle_t *handle)
630{
631    char *devName;
632    unsigned flags = 0;
633    int err = NO_ERROR;
634
635    if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
636        err = setHDMIChannelCount();
637        if(err != OK) {
638            ALOGE("setHDMIChannelCount err = %d", err);
639            return err;
640        }
641    }
642    /* No need to call s_close for LPA as pcm device open and close is handled by LPAPlayer in stagefright */
643    if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA))
644    ||(!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
645        ALOGV("s_open: Opening LPA /Tunnel playback");
646        return NO_ERROR;
647    }
648
649    s_close(handle);
650
651    ALOGV("s_open: handle %p", handle);
652
653    // ASoC multicomponent requires a valid path (frontend/backend) for
654    // the device to be opened
655
656    // The PCM stream is opened in blocking mode, per ALSA defaults.  The
657    // AudioFlinger seems to assume blocking mode too, so asynchronous mode
658    // should not be used.
659    if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
660        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
661        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
662        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
663        ALOGV("LPA/tunnel use case");
664        flags |= PCM_MMAP;
665        flags |= DEBUG_ON;
666    } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) ||
667        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) ||
668        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
669        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
670        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
671        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
672        ALOGV("Music case");
673        flags = PCM_OUT;
674    } else {
675        flags = PCM_IN;
676    }
677    if (handle->channels == 1) {
678        flags |= PCM_MONO;
679    }
680    else if (handle->channels == 4 ) {
681        flags |= PCM_QUAD;
682    } else if (handle->channels == 6 ) {
683#ifdef QCOM_SSR_ENABLED
684        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
685            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
686            flags |= PCM_QUAD;
687        } else {
688            flags |= PCM_5POINT1;
689        }
690#else
691        flags |= PCM_5POINT1;
692#endif
693    }
694    else {
695        flags |= PCM_STEREO;
696    }
697    if (deviceName(handle, flags, &devName) < 0) {
698        ALOGE("Failed to get pcm device node: %s", devName);
699        return NO_INIT;
700    }
701    if (devName != NULL) {
702        handle->handle = pcm_open(flags, (char*)devName);
703    } else {
704        ALOGE("Failed to get pcm device node");
705        return NO_INIT;
706    }
707
708    if (!handle->handle) {
709        ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
710        free(devName);
711        return NO_INIT;
712    }
713
714    handle->handle->flags = flags;
715    err = setHardwareParams(handle);
716
717    if (err == NO_ERROR) {
718        err = setSoftwareParams(handle);
719    }
720
721    if(err != NO_ERROR) {
722        ALOGE("Set HW/SW params failed: Closing the pcm stream");
723        s_standby(handle);
724    }
725
726    free(devName);
727    return NO_ERROR;
728}
729
730static status_t s_start_voip_call(alsa_handle_t *handle)
731{
732
733    char* devName;
734    char* devName1;
735    unsigned flags = 0;
736    int err = NO_ERROR;
737    uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE];
738
739    s_close(handle);
740    flags = PCM_OUT;
741    flags |= PCM_MONO;
742    ALOGV("s_open:s_start_voip_call  handle %p", handle);
743
744    if (deviceName(handle, flags, &devName) < 0) {
745         ALOGE("Failed to get pcm device node");
746         return NO_INIT;
747    }
748
749    if (devName != NULL) {
750        handle->handle = pcm_open(flags, (char*)devName);
751    } else {
752         ALOGE("Failed to get pcm device node");
753         return NO_INIT;
754    }
755
756     if (!handle->handle) {
757          free(devName);
758          ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
759          return NO_INIT;
760     }
761
762     if (!pcm_ready(handle->handle)) {
763         ALOGE(" pcm ready failed");
764     }
765
766     handle->handle->flags = flags;
767     err = setHardwareParams(handle);
768
769     if (err == NO_ERROR) {
770         err = setSoftwareParams(handle);
771     }
772
773     err = pcm_prepare(handle->handle);
774     if(err != NO_ERROR) {
775         ALOGE("DEVICE_OUT_DIRECTOUTPUT: pcm_prepare failed");
776     }
777
778     /* first write required start dsp */
779     memset(&voc_pkt,0,sizeof(voc_pkt));
780     pcm_write(handle->handle,&voc_pkt,handle->handle->period_size);
781     handle->rxHandle = handle->handle;
782     free(devName);
783     ALOGV("s_open: DEVICE_IN_COMMUNICATION ");
784     flags = PCM_IN;
785     flags |= PCM_MONO;
786     handle->handle = 0;
787
788     if (deviceName(handle, flags, &devName1) < 0) {
789        ALOGE("Failed to get pcm device node");
790        return NO_INIT;
791     }
792    if (devName != NULL) {
793        handle->handle = pcm_open(flags, (char*)devName1);
794    } else {
795         ALOGE("Failed to get pcm device node");
796         return NO_INIT;
797    }
798
799     if (!handle->handle) {
800         free(devName);
801         ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
802         return NO_INIT;
803     }
804
805     if (!pcm_ready(handle->handle)) {
806        ALOGE(" pcm ready in failed");
807     }
808
809     handle->handle->flags = flags;
810
811     err = setHardwareParams(handle);
812
813     if (err == NO_ERROR) {
814         err = setSoftwareParams(handle);
815     }
816
817
818     err = pcm_prepare(handle->handle);
819     if(err != NO_ERROR) {
820         ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed");
821     }
822
823     /* first read required start dsp */
824     memset(&voc_pkt,0,sizeof(voc_pkt));
825     pcm_read(handle->handle,&voc_pkt,handle->handle->period_size);
826     return NO_ERROR;
827}
828
829static status_t s_start_voice_call(alsa_handle_t *handle)
830{
831    char* devName;
832    unsigned flags = 0;
833    int err = NO_ERROR;
834
835    ALOGV("s_start_voice_call: handle %p", handle);
836
837    // ASoC multicomponent requires a valid path (frontend/backend) for
838    // the device to be opened
839
840    flags = PCM_OUT | PCM_MONO;
841    if (deviceName(handle, flags, &devName) < 0) {
842        ALOGE("Failed to get pcm device node");
843        return NO_INIT;
844    }
845    if (devName != NULL) {
846        handle->handle = pcm_open(flags, (char*)devName);
847    } else {
848         ALOGE("Failed to get pcm device node");
849         return NO_INIT;
850    }
851    if (!handle->handle) {
852        ALOGE("s_start_voicecall: could not open PCM device");
853        goto Error;
854    }
855
856    handle->handle->flags = flags;
857    err = setHardwareParams(handle);
858    if(err != NO_ERROR) {
859        ALOGE("s_start_voice_call: setHardwareParams failed");
860        goto Error;
861    }
862
863    err = setSoftwareParams(handle);
864    if(err != NO_ERROR) {
865        ALOGE("s_start_voice_call: setSoftwareParams failed");
866        goto Error;
867    }
868
869    err = pcm_prepare(handle->handle);
870    if(err != NO_ERROR) {
871        ALOGE("s_start_voice_call: pcm_prepare failed");
872        goto Error;
873    }
874
875    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
876        ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
877        goto Error;
878    }
879
880    // Store the PCM playback device pointer in rxHandle
881    handle->rxHandle = handle->handle;
882    free(devName);
883
884    // Open PCM capture device
885    flags = PCM_IN | PCM_MONO;
886    if (deviceName(handle, flags, &devName) < 0) {
887        ALOGE("Failed to get pcm device node");
888        goto Error;
889    }
890    if (devName != NULL) {
891        handle->handle = pcm_open(flags, (char*)devName);
892    } else {
893         ALOGE("Failed to get pcm device node");
894         return NO_INIT;
895    }
896    if (!handle->handle) {
897        free(devName);
898        goto Error;
899    }
900
901    handle->handle->flags = flags;
902    err = setHardwareParams(handle);
903    if(err != NO_ERROR) {
904        ALOGE("s_start_voice_call: setHardwareParams failed");
905        goto Error;
906    }
907
908    err = setSoftwareParams(handle);
909    if(err != NO_ERROR) {
910        ALOGE("s_start_voice_call: setSoftwareParams failed");
911        goto Error;
912    }
913
914    err = pcm_prepare(handle->handle);
915    if(err != NO_ERROR) {
916        ALOGE("s_start_voice_call: pcm_prepare failed");
917        goto Error;
918    }
919
920    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
921        ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
922        goto Error;
923    }
924
925    if (platform_is_Fusion3()) {
926#ifdef QCOM_CSDCLIENT_ENABLED
927        if (csd_start_voice == NULL) {
928            ALOGE("dlsym:Error:%s Loading csd_client_start_voice", dlerror());
929        } else {
930            err = csd_start_voice();
931            if (err < 0){
932                ALOGE("s_start_voice_call: csd_client error %d\n", err);
933                goto Error;
934            }
935        }
936#endif
937    }
938
939    free(devName);
940    return NO_ERROR;
941
942Error:
943    ALOGE("s_start_voice_call: Failed to initialize ALSA device '%s'", devName);
944    free(devName);
945    s_close(handle);
946    return NO_INIT;
947}
948
949static status_t s_start_fm(alsa_handle_t *handle)
950{
951    char *devName;
952    unsigned flags = 0;
953    int err = NO_ERROR;
954
955    ALOGV("s_start_fm: handle %p", handle);
956
957    // ASoC multicomponent requires a valid path (frontend/backend) for
958    // the device to be opened
959
960    flags = PCM_OUT | PCM_STEREO;
961    if (deviceName(handle, flags, &devName) < 0) {
962        ALOGE("Failed to get pcm device node");
963        goto Error;
964    }
965    if (devName != NULL) {
966        handle->handle = pcm_open(flags, (char*)devName);
967    } else {
968         ALOGE("Failed to get pcm device node");
969         return NO_INIT;
970    }
971    if (!handle->handle) {
972        ALOGE("s_start_fm: could not open PCM device");
973        goto Error;
974    }
975
976    handle->handle->flags = flags;
977    err = setHardwareParams(handle);
978    if(err != NO_ERROR) {
979        ALOGE("s_start_fm: setHardwareParams failed");
980        goto Error;
981    }
982
983    err = setSoftwareParams(handle);
984    if(err != NO_ERROR) {
985        ALOGE("s_start_fm: setSoftwareParams failed");
986        goto Error;
987    }
988
989    err = pcm_prepare(handle->handle);
990    if(err != NO_ERROR) {
991        ALOGE("s_start_fm: setSoftwareParams failed");
992        goto Error;
993    }
994
995    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
996        ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n");
997        goto Error;
998    }
999
1000    // Store the PCM playback device pointer in rxHandle
1001    handle->rxHandle = handle->handle;
1002    free(devName);
1003
1004    // Open PCM capture device
1005    flags = PCM_IN | PCM_STEREO;
1006    if (deviceName(handle, flags, &devName) < 0) {
1007        ALOGE("Failed to get pcm device node");
1008        goto Error;
1009    }
1010    if (devName != NULL) {
1011        handle->handle = pcm_open(flags, (char*)devName);
1012    } else {
1013         ALOGE("Failed to get pcm device node");
1014         return NO_INIT;
1015    }
1016    if (!handle->handle) {
1017        goto Error;
1018    }
1019
1020    handle->handle->flags = flags;
1021    err = setHardwareParams(handle);
1022    if(err != NO_ERROR) {
1023        ALOGE("s_start_fm: setHardwareParams failed");
1024        goto Error;
1025    }
1026
1027    err = setSoftwareParams(handle);
1028    if(err != NO_ERROR) {
1029        ALOGE("s_start_fm: setSoftwareParams failed");
1030        goto Error;
1031    }
1032
1033    err = pcm_prepare(handle->handle);
1034    if(err != NO_ERROR) {
1035        ALOGE("s_start_fm: pcm_prepare failed");
1036        goto Error;
1037    }
1038
1039    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
1040        ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n");
1041        goto Error;
1042    }
1043
1044    s_set_fm_vol(fmVolume);
1045    free(devName);
1046    return NO_ERROR;
1047
1048Error:
1049    free(devName);
1050    s_close(handle);
1051    return NO_INIT;
1052}
1053
1054static status_t s_set_fm_vol(int value)
1055{
1056    status_t err = NO_ERROR;
1057
1058    ALSAControl control("/dev/snd/controlC0");
1059    control.set("Internal FM RX Volume",value,0);
1060    fmVolume = value;
1061
1062    return err;
1063}
1064
1065static status_t s_set_lpa_vol(int value)
1066{
1067    status_t err = NO_ERROR;
1068
1069    ALSAControl control("/dev/snd/controlC0");
1070    control.set("LPA RX Volume",value,0);
1071
1072    return err;
1073}
1074
1075static status_t s_start(alsa_handle_t *handle)
1076{
1077    status_t err = NO_ERROR;
1078
1079    if(!handle->handle) {
1080        ALOGE("No active PCM driver to start");
1081        return err;
1082    }
1083
1084    err = pcm_prepare(handle->handle);
1085
1086    return err;
1087}
1088
1089static status_t s_close(alsa_handle_t *handle)
1090{
1091    int ret;
1092    status_t err = NO_ERROR;
1093     struct pcm *h = handle->rxHandle;
1094
1095    handle->rxHandle = 0;
1096    ALOGV("s_close: handle %p h %p", handle, h);
1097    if (h) {
1098        if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) ||
1099             !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) &&
1100            platform_is_Fusion3()) {
1101#ifdef QCOM_CSDCLIENT_ENABLED
1102            if (csd_stop_voice == NULL) {
1103                ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
1104            } else {
1105                err = csd_stop_voice();
1106                if (err < 0) {
1107                    ALOGE("s_close: csd_client error %d\n", err);
1108                }
1109            }
1110#endif
1111        }
1112
1113        ALOGV("s_close rxHandle\n");
1114        err = pcm_close(h);
1115        if(err != NO_ERROR) {
1116            ALOGE("s_close: pcm_close failed for rxHandle with err %d", err);
1117        }
1118    }
1119
1120    h = handle->handle;
1121    handle->handle = 0;
1122
1123    if (h) {
1124        ALOGV("s_close handle h %p\n", h);
1125        err = pcm_close(h);
1126        if(err != NO_ERROR) {
1127            ALOGE("s_close: pcm_close failed for handle with err %d", err);
1128        }
1129
1130        disableDevice(handle);
1131    } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
1132              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
1133              (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
1134              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))){
1135        disableDevice(handle);
1136    }
1137
1138    return err;
1139}
1140
1141/*
1142    this is same as s_close, but don't discard
1143    the device/mode info. This way we can still
1144    close the device, hit idle and power-save, reopen the pcm
1145    for the same device/mode after resuming
1146*/
1147static status_t s_standby(alsa_handle_t *handle)
1148{
1149    int ret;
1150    status_t err = NO_ERROR;
1151    struct pcm *h = handle->rxHandle;
1152    handle->rxHandle = 0;
1153    ALOGV("s_standby: handle %p h %p", handle, h);
1154    if (h) {
1155        ALOGD("s_standby  rxHandle\n");
1156        err = pcm_close(h);
1157        if(err != NO_ERROR) {
1158            ALOGE("s_standby: pcm_close failed for rxHandle with err %d", err);
1159        }
1160    }
1161
1162    h = handle->handle;
1163    handle->handle = 0;
1164
1165    if (h) {
1166          ALOGV("s_standby handle h %p\n", h);
1167        err = pcm_close(h);
1168        if(err != NO_ERROR) {
1169            ALOGE("s_standby: pcm_close failed for handle with err %d", err);
1170        }
1171        disableDevice(handle);
1172    } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
1173              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
1174              (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
1175              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
1176        disableDevice(handle);
1177    }
1178
1179    return err;
1180}
1181
1182static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode)
1183{
1184    status_t status = NO_ERROR;
1185
1186    ALOGD("s_route: devices 0x%x in mode %d", devices, mode);
1187    callMode = mode;
1188    switchDevice(handle, devices, mode);
1189    return status;
1190}
1191
1192int getUseCaseType(const char *useCase)
1193{
1194    ALOGD("use case is %s\n", useCase);
1195    if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
1196            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
1197        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
1198            MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) ||
1199        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
1200            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
1201        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
1202            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
1203        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
1204            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
1205        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
1206            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
1207        !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
1208            MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
1209        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
1210            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
1211        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
1212            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
1213        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
1214            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
1215        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
1216            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
1217        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
1218            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
1219        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
1220            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
1221        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
1222            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
1223        return USECASE_TYPE_RX;
1224    } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
1225            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
1226        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
1227            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
1228        !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
1229            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
1230        !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
1231            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
1232        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
1233            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
1234        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
1235            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
1236        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
1237            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
1238        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
1239            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
1240        return USECASE_TYPE_TX;
1241    } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
1242            MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
1243        !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
1244            MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
1245        !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
1246            MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
1247        !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
1248            MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
1249        !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
1250            MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
1251        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1252            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
1253        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
1254            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
1255        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
1256            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
1257        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
1258            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
1259        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1260            MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
1261        !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
1262            MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
1263        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1264            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
1265        return (USECASE_TYPE_RX | USECASE_TYPE_TX);
1266    } else {
1267        ALOGE("unknown use case %s\n", useCase);
1268        return 0;
1269    }
1270}
1271
1272static void disableDevice(alsa_handle_t *handle)
1273{
1274    unsigned usecase_type = 0;
1275    int i, mods_size;
1276    char *useCase;
1277    const char **mods_list;
1278
1279    snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
1280    if (useCase != NULL) {
1281        if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) {
1282            snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
1283        } else {
1284            snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase);
1285        }
1286        free(useCase);
1287        snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
1288        if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE,
1289               strlen(SND_USE_CASE_VERB_INACTIVE)))
1290            usecase_type |= getUseCaseType(useCase);
1291        mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
1292        ALOGV("Number of modifiers %d\n", mods_size);
1293        if (mods_size) {
1294            for(i = 0; i < mods_size; i++) {
1295                ALOGV("index %d modifier %s\n", i, mods_list[i]);
1296                usecase_type |= getUseCaseType(mods_list[i]);
1297            }
1298        }
1299        ALOGV("usecase_type is %d\n", usecase_type);
1300        if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(curTxUCMDevice, "None", 4)))
1301            snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice);
1302        if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(curRxUCMDevice, "None", 4)))
1303            snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice);
1304    } else {
1305        ALOGE("Invalid state, no valid use case found to disable");
1306    }
1307    free(useCase);
1308}
1309
1310char *getUCMDevice(uint32_t devices, int input, char *rxDevice)
1311{
1312    bool is_tmus = s_is_tmus();
1313
1314    if (!input) {
1315        if (!(mDevSettingsFlag & TTY_OFF) &&
1316            (callMode == AudioSystem::MODE_IN_CALL) &&
1317            ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
1318             (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
1319#ifdef QCOM_ANC_HEADSET_ENABLED
1320             ||
1321             (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
1322             (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
1323#endif
1324             if (mDevSettingsFlag & TTY_VCO) {
1325                 return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
1326             } else if (mDevSettingsFlag & TTY_FULL) {
1327                 return strdup(SND_USE_CASE_DEV_TTY_FULL_RX);
1328             } else if (mDevSettingsFlag & TTY_HCO) {
1329                 return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */
1330             }
1331        }else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
1332                  (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) {
1333             return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
1334        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
1335            ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
1336            (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
1337            if (mDevSettingsFlag & ANC_FLAG) {
1338                return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
1339            } else {
1340                return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */
1341            }
1342        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
1343            ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) {
1344            return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER);
1345#ifdef QCOM_ANC_HEADSET_ENABLED
1346        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
1347            ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
1348            (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
1349            return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
1350        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
1351                 (devices & AudioSystem::DEVICE_OUT_FM_TX)) {
1352            return strdup(SND_USE_CASE_DEV_SPEAKER_FM_TX); /* COMBO SPEAKER+FM_TX RX */
1353#endif
1354        } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
1355            if (callMode == AudioSystem::MODE_IN_CALL) {
1356                if(is_tmus)
1357                    return strdup(SND_USE_CASE_DEV_VOC_EARPIECE_TMUS); /* Voice HANDSET RX for TMUS */
1358                else
1359                    return strdup(SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */
1360            } else
1361                return strdup(SND_USE_CASE_DEV_EARPIECE); /* HANDSET RX */
1362        } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
1363            if (callMode == AudioSystem::MODE_IN_CALL) {
1364                return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
1365            } else
1366                return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
1367        } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
1368                   (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) {
1369            if (mDevSettingsFlag & ANC_FLAG) {
1370                if (callMode == AudioSystem::MODE_IN_CALL) {
1371                    return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
1372                } else
1373                    return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
1374            } else {
1375                if (callMode == AudioSystem::MODE_IN_CALL) {
1376                    return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */
1377                } else
1378                    return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
1379            }
1380#ifdef QCOM_ANC_HEADSET_ENABLED
1381        } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
1382                   (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) {
1383            if (callMode == AudioSystem::MODE_IN_CALL) {
1384                return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
1385            } else
1386                return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
1387#endif
1388        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
1389                  (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
1390                  (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
1391            if (btsco_samplerate == BTSCO_RATE_16KHZ)
1392                return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/
1393            else
1394                return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/
1395        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP) ||
1396                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) ||
1397#ifdef QCOM_VOIP_ENABLED
1398                   (devices & AudioSystem::DEVICE_OUT_DIRECTOUTPUT) ||
1399#endif
1400                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
1401            /* Nothing to be done, use current active device */
1402            if (strncmp(curRxUCMDevice, "None", 4)) {
1403                return strdup(curRxUCMDevice);
1404            }
1405        } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
1406            return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */
1407#ifdef QCOM_PROXY_DEVICE_ENABLED
1408        } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
1409            return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
1410#endif
1411#ifdef QCOM_FM_TX_ENABLED
1412        } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) {
1413            return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */
1414#endif
1415        } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) {
1416            if (callMode == AudioSystem::MODE_IN_CALL) {
1417                return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
1418            } else
1419                return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
1420        } else {
1421            ALOGD("No valid output device: %u", devices);
1422        }
1423    } else {
1424        if (!(mDevSettingsFlag & TTY_OFF) &&
1425            (callMode == AudioSystem::MODE_IN_CALL) &&
1426            ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)
1427#ifdef QCOM_ANC_HEADSET_ENABLED
1428              || (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)
1429#endif
1430            )) {
1431             if (mDevSettingsFlag & TTY_HCO) {
1432                 return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX);
1433             } else if (mDevSettingsFlag & TTY_FULL) {
1434                 return strdup(SND_USE_CASE_DEV_TTY_FULL_TX);
1435             } else if (mDevSettingsFlag & TTY_VCO) {
1436                 if (!strncmp(mic_type, "analog", 6)) {
1437                     return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX);
1438                 } else {
1439                     return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX);
1440                 }
1441             }
1442        } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
1443            if (!strncmp(mic_type, "analog", 6)) {
1444                return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
1445            } else {
1446                if (mDevSettingsFlag & DMIC_FLAG) {
1447                    if(callMode == AudioSystem::MODE_IN_CALL) {
1448#ifdef USES_FLUENCE_INCALL
1449                        if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
1450                            if(is_tmus)
1451                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_TMUS); /* DUALMIC EF TX */
1452                            else
1453                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
1454                        } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
1455                            return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
1456                        } else {
1457                            return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
1458                        }
1459#endif
1460                    }
1461                    if (((rxDevice != NULL) &&
1462                        !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
1463                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
1464                        !strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
1465                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) {
1466                        if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
1467                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
1468// TODO: check if different ACDB settings are needed when speaker is enabled
1469                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC);
1470                            } else {
1471                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE);
1472                            }
1473                        } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
1474                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
1475                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC);
1476                            } else {
1477                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE);
1478                            }
1479                        }
1480                    } else {
1481                        if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
1482                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
1483                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_VREC);
1484                            } else {
1485                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE);
1486                            }
1487                        } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
1488                            if (input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
1489                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE_VREC);
1490                            } else {
1491                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE);
1492                            }
1493                        }
1494                    }
1495                } else if (mDevSettingsFlag & QMIC_FLAG){
1496                    return strdup(SND_USE_CASE_DEV_QUAD_MIC);
1497                }
1498#ifdef QCOM_SSR_ENABLED
1499                else if (mDevSettingsFlag & SSRQMIC_FLAG){
1500                    ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices);
1501                    // Mapping for quad mic input device.
1502                    return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */
1503                }
1504#endif
1505#ifdef SEPERATED_AUDIO_INPUT
1506                if(input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
1507                    return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
1508                }
1509#endif
1510                else {
1511                    return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
1512                }
1513            }
1514        } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) {
1515            return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */
1516#ifdef QCOM_ANC_HEADSET_ENABLED
1517        } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
1518            return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
1519#endif
1520        } else if (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
1521            if (callMode == AudioSystem::MODE_IN_CALL) {
1522                return strdup(SND_USE_CASE_DEV_VOC_HEADSET); /* Voice HEADSET TX */
1523            } else
1524                return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
1525        } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
1526             if (btsco_samplerate == BTSCO_RATE_16KHZ)
1527                 return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/
1528             else
1529                 return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/
1530#ifdef QCOM_USBAUDIO_ENABLED
1531        } else if ((devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
1532                   (devices & AudioSystem::DEVICE_IN_PROXY)) {
1533            return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
1534#endif
1535        } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) ||
1536                   (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) {
1537            /* Nothing to be done, use current active device */
1538            if (strncmp(curTxUCMDevice, "None", 4)) {
1539                return strdup(curTxUCMDevice);
1540            }
1541#ifdef QCOM_FM_ENABLED
1542        } else if ((devices & AudioSystem::DEVICE_IN_FM_RX) ||
1543                   (devices & AudioSystem::DEVICE_IN_FM_RX_A2DP)) {
1544            /* Nothing to be done, use current tx device or set dummy device */
1545            if (strncmp(curTxUCMDevice, "None", 4)) {
1546                return strdup(curTxUCMDevice);
1547            } else {
1548                return strdup(SND_USE_CASE_DEV_DUMMY_TX);
1549            }
1550#endif
1551        } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) ||
1552                   (devices & AudioSystem::DEVICE_IN_BACK_MIC)) {
1553            ALOGI("No proper mapping found with UCM device list, setting default");
1554            if (!strncmp(mic_type, "analog", 6)) {
1555                return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
1556            } else {
1557                if (callMode == AudioSystem::MODE_IN_CALL) {
1558                    return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */
1559#ifdef SEPERATED_AUDIO_INPUT
1560                } else if(input_source == AUDIO_SOURCE_CAMCORDER) {
1561                    return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
1562#endif
1563                } else
1564                    return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
1565            }
1566        } else {
1567            ALOGD("No valid input device: %u", devices);
1568        }
1569    }
1570    return NULL;
1571}
1572
1573void s_set_voice_volume(int vol)
1574{
1575    int err = 0;
1576    ALOGV("s_set_voice_volume: volume %d", vol);
1577    ALSAControl control("/dev/snd/controlC0");
1578    control.set("Voice Rx Volume", vol, 0);
1579
1580    if (platform_is_Fusion3()) {
1581#ifdef QCOM_CSDCLIENT_ENABLED
1582        if (csd_volume == NULL) {
1583            ALOGE("dlsym:Error:%s Loading csd_client_volume", dlerror());
1584        } else {
1585            err = csd_volume(vol);
1586            if (err < 0) {
1587                ALOGE("s_set_voice_volume: csd_client error %d", err);
1588            }
1589        }
1590#endif
1591    }
1592}
1593
1594void s_set_volte_volume(int vol)
1595{
1596    ALOGV("s_set_volte_volume: volume %d", vol);
1597    ALSAControl control("/dev/snd/controlC0");
1598    control.set("VoLTE Rx Volume", vol, 0);
1599}
1600
1601
1602void s_set_voip_volume(int vol)
1603{
1604    ALOGV("s_set_voip_volume: volume %d", vol);
1605    ALSAControl control("/dev/snd/controlC0");
1606    control.set("Voip Rx Volume", vol, 0);
1607}
1608void s_set_mic_mute(int state)
1609{
1610    int err = 0;
1611    ALOGV("s_set_mic_mute: state %d", state);
1612    ALSAControl control("/dev/snd/controlC0");
1613    control.set("Voice Tx Mute", state, 0);
1614
1615    if (platform_is_Fusion3()) {
1616#ifdef QCOM_CSDCLIENT_ENABLED
1617        if (csd_mic_mute == NULL) {
1618            ALOGE("dlsym:Error:%s Loading csd_mic_mute", dlerror());
1619        } else {
1620            err=csd_mic_mute(state);
1621            if (err < 0) {
1622                ALOGE("s_set_mic_mute: csd_client error %d", err);
1623            }
1624        }
1625#endif
1626    }
1627}
1628void s_set_volte_mic_mute(int state)
1629{
1630    ALOGV("s_set_volte_mic_mute: state %d", state);
1631    ALSAControl control("/dev/snd/controlC0");
1632    control.set("VoLTE Tx Mute", state, 0);
1633}
1634
1635void s_set_voip_mic_mute(int state)
1636{
1637    ALOGV("s_set_voip_mic_mute: state %d", state);
1638    ALSAControl control("/dev/snd/controlC0");
1639    control.set("Voip Tx Mute", state, 0);
1640}
1641
1642void s_set_voip_config(int mode, int rate)
1643{
1644    ALOGV("s_set_voip_config: mode %d,rate %d", mode, rate);
1645    ALSAControl control("/dev/snd/controlC0");
1646    char** setValues;
1647    setValues = (char**)malloc(2*sizeof(char*));
1648    if (setValues == NULL) {
1649          return;
1650    }
1651    setValues[0] = (char*)malloc(4*sizeof(char));
1652    if (setValues[0] == NULL) {
1653          free(setValues);
1654          return;
1655    }
1656
1657    setValues[1] = (char*)malloc(8*sizeof(char));
1658    if (setValues[1] == NULL) {
1659          free(setValues);
1660          free(setValues[0]);
1661          return;
1662    }
1663
1664    sprintf(setValues[0], "%d",mode);
1665    sprintf(setValues[1], "%d",rate);
1666
1667    control.setext("Voip Mode Rate Config", 2, setValues);
1668    free(setValues[1]);
1669    free(setValues[0]);
1670    free(setValues);
1671    return;
1672}
1673
1674void s_set_btsco_rate(int rate)
1675{
1676    btsco_samplerate = rate;
1677}
1678
1679void s_enable_wide_voice(bool flag)
1680{
1681    int err = 0;
1682
1683    ALOGV("s_enable_wide_voice: flag %d", flag);
1684    ALSAControl control("/dev/snd/controlC0");
1685    if(flag == true) {
1686        control.set("Widevoice Enable", 1, 0);
1687    } else {
1688        control.set("Widevoice Enable", 0, 0);
1689    }
1690
1691    if (platform_is_Fusion3()) {
1692#ifdef QCOM_CSDCLIENT_ENABLED
1693        if (csd_wide_voice == NULL) {
1694            ALOGE("dlsym:Error:%s Loading csd_wide_voice", dlerror());
1695        } else {
1696            err = csd_wide_voice(flag);
1697            if (err < 0) {
1698                ALOGE("enableWideVoice: csd_client_wide_voice error %d", err);
1699            }
1700        }
1701#endif
1702    }
1703}
1704
1705void s_set_voc_rec_mode(uint8_t mode)
1706{
1707    ALOGV("s_set_voc_rec_mode: mode %d", mode);
1708    ALSAControl control("/dev/snd/controlC0");
1709    control.set("Incall Rec Mode", mode, 0);
1710}
1711
1712void s_enable_fens(bool flag)
1713{
1714    int err = 0;
1715
1716    ALOGV("s_enable_fens: flag %d", flag);
1717    ALSAControl control("/dev/snd/controlC0");
1718    if(flag == true) {
1719        control.set("FENS Enable", 1, 0);
1720    } else {
1721        control.set("FENS Enable", 0, 0);
1722    }
1723
1724    if (platform_is_Fusion3()) {
1725#ifdef QCOM_CSDCLIENT_ENABLED
1726        if (csd_fens == NULL) {
1727            ALOGE("dlsym:Error:%s Loading csd_fens", dlerror());
1728        } else {
1729            err = csd_fens(flag);
1730            if (err < 0) {
1731                ALOGE("s_enable_fens: csd_client error %d", err);
1732            }
1733        }
1734#endif
1735    }
1736}
1737
1738void s_enable_slow_talk(bool flag)
1739{
1740    int err = 0;
1741
1742    ALOGV("s_enable_slow_talk: flag %d", flag);
1743    ALSAControl control("/dev/snd/controlC0");
1744    if(flag == true) {
1745        control.set("Slowtalk Enable", 1, 0);
1746    } else {
1747        control.set("Slowtalk Enable", 0, 0);
1748    }
1749
1750    if (platform_is_Fusion3()) {
1751#ifdef QCOM_CSDCLIENT_ENABLED
1752        if (csd_slow_talk == NULL) {
1753            ALOGE("dlsym:Error:%s Loading csd_slow_talk", dlerror());
1754        } else {
1755            err = csd_slow_talk(flag);
1756            if (err < 0) {
1757                ALOGE("s_enable_slow_talk: csd_client error %d", err);
1758            }
1759        }
1760#endif
1761    }
1762}
1763
1764void s_set_flags(uint32_t flags)
1765{
1766    ALOGV("s_set_flags: flags %d", flags);
1767    mDevSettingsFlag = flags;
1768}
1769
1770static status_t s_set_compressed_vol(int value)
1771{
1772    status_t err = NO_ERROR;
1773
1774    ALSAControl control("/dev/snd/controlC0");
1775    control.set("COMPRESSED RX Volume",value,0);
1776
1777    return err;
1778}
1779
1780#ifdef SEPERATED_AUDIO_INPUT
1781void s_setInput(int input)
1782{
1783    input_source = input;
1784    ALOGD("s_setInput() : input_source = %d",input_source);
1785}
1786#endif
1787
1788#ifdef QCOM_CSDCLIENT_ENABLED
1789static void  s_set_csd_handle(void* handle)
1790{
1791    csd_handle = static_cast<void*>(handle);
1792    ALOGI("%s csd_handle: %p", __func__, csd_handle);
1793
1794    csd_disable_device = (int (*)())::dlsym(csd_handle,"csd_client_disable_device");
1795    csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(csd_handle,"csd_client_enable_device");
1796    csd_start_voice = (int (*)())::dlsym(csd_handle,"csd_client_start_voice");
1797    csd_stop_voice = (int (*)())::dlsym(csd_handle,"csd_client_stop_voice");
1798    csd_volume = (int (*)(int))::dlsym(csd_handle,"csd_client_volume");
1799    csd_mic_mute = (int (*)(int))::dlsym(csd_handle,"csd_client_mic_mute");
1800    csd_wide_voice = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_wide_voice");
1801    csd_fens = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_fens");
1802    csd_slow_talk = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_slow_talk");
1803}
1804#endif
1805
1806static bool s_is_tmus()
1807{
1808    char value[128];
1809    bool ret = false;
1810
1811    if (mccmnc == 0) {
1812        property_get("gsm.sim.operator.numeric",value,"0");
1813        mccmnc = atoi(value);
1814    }
1815
1816    ALOGD("%s: mnc_mcc :  %d", __FUNCTION__, mccmnc);
1817    switch(mccmnc)
1818    {
1819    //TMUS MCC(310), MNC(490, 260, 026)
1820    case 310490:
1821    case 310260:
1822    case 310026:
1823        ret = true;
1824        break;
1825    default:
1826        ret = false;
1827        break;
1828    }
1829
1830    return ret;
1831}
1832
1833}
1834