blob: 71b944c4d3c29d8270f0680c39a611f9a3245edb [file] [log] [blame]
Iliyan Malchev4765c432012-06-11 14:36:16 -07001/* AudioHardwareALSA.cpp
2 **
3 ** Copyright 2008-2010 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#include <math.h>
27
Ajay Dudani9746c472012-06-18 16:01:16 -070028#define LOG_TAG "AudioHardwareALSA"
Iliyan Malchev4765c432012-06-11 14:36:16 -070029//#define LOG_NDEBUG 0
Ajay Dudani9746c472012-06-18 16:01:16 -070030#define LOG_NDDEBUG 0
Iliyan Malchev4765c432012-06-11 14:36:16 -070031#include <utils/Log.h>
32#include <utils/String8.h>
33#include <sys/prctl.h>
34#include <sys/resource.h>
35#include <sys/poll.h>
36#include <sys/ioctl.h>
37#include <cutils/properties.h>
38#include <media/AudioRecord.h>
39#include <hardware_legacy/power.h>
40
41#include "AudioHardwareALSA.h"
Ajay Dudani9746c472012-06-18 16:01:16 -070042#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070043#include "AudioUsbALSA.h"
Ajay Dudani9746c472012-06-18 16:01:16 -070044#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -070045
Iliyan Malchev4765c432012-06-11 14:36:16 -070046extern "C"
47{
48 //
49 // Function for dlsym() to look up for creating a new AudioHardwareInterface.
50 //
51 android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {
52 return android_audio_legacy::AudioHardwareALSA::create();
53 }
SathishKumar Mani5ff7a022012-09-14 11:36:35 -070054#ifdef QCOM_ACDB_ENABLED
55 static int (*acdb_init)();
56 static void (*acdb_deallocate)();
57#endif
58#ifdef QCOM_CSDCLIENT_ENABLED
59 static int (*csd_start_playback)();
60 static int (*csd_stop_playback)();
61#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -070062} // extern "C"
63
64namespace android_audio_legacy
65{
66
67// ----------------------------------------------------------------------------
68
69AudioHardwareInterface *AudioHardwareALSA::create() {
70 return new AudioHardwareALSA();
71}
72
73AudioHardwareALSA::AudioHardwareALSA() :
74 mALSADevice(0),mVoipStreamCount(0),mVoipMicMute(false),mVoipBitRate(0)
SathishKumar Mani5ff7a022012-09-14 11:36:35 -070075 ,mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL)
Iliyan Malchev4765c432012-06-11 14:36:16 -070076{
77 FILE *fp;
78 char soundCardInfo[200];
79 hw_module_t *module;
80 char platform[128], baseband[128];
81 int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
82 (hw_module_t const**)&module);
83 int codec_rev = 2;
Iliyan Malchev4113f342012-06-11 14:39:47 -070084 ALOGD("hw_get_module(ALSA_HARDWARE_MODULE_ID) returned err %d", err);
Iliyan Malchev4765c432012-06-11 14:36:16 -070085 if (err == 0) {
86 hw_device_t* device;
87 err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);
88 if (err == 0) {
89 mALSADevice = (alsa_device_t *)device;
90 mALSADevice->init(mALSADevice, mDeviceList);
91 mCSCallActive = 0;
92 mVolteCallActive = 0;
93 mIsFmActive = 0;
94 mDevSettingsFlag = 0;
Ajay Dudani9746c472012-06-18 16:01:16 -070095#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070096 mAudioUsbALSA = new AudioUsbALSA();
Ajay Dudani9746c472012-06-18 16:01:16 -070097 musbPlaybackState = 0;
98 musbRecordingState = 0;
99#endif
ty.lee924f7982012-08-01 23:15:30 +0900100#ifdef USES_FLUENCE_INCALL
101 mDevSettingsFlag |= TTY_OFF | DMIC_FLAG;
102#else
Iliyan Malchev4765c432012-06-11 14:36:16 -0700103 mDevSettingsFlag |= TTY_OFF;
ty.lee924f7982012-08-01 23:15:30 +0900104#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700105 mBluetoothVGS = false;
106 mFusion3Platform = false;
Ajay Dudani9746c472012-06-18 16:01:16 -0700107
108#ifdef QCOM_ACDB_ENABLED
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700109 mAcdbHandle = ::dlopen("/system/lib/libacdbloader.so", RTLD_NOW);
110 if (mAcdbHandle == NULL) {
111 ALOGE("AudioHardware: DLOPEN not successful for ACDBLOADER");
112 } else {
113 ALOGD("AudioHardware: DLOPEN successful for ACDBLOADER");
114 acdb_init = (int (*)())::dlsym(mAcdbHandle,"acdb_loader_init_ACDB");
115 if (acdb_init == NULL) {
116 ALOGE("dlsym:Error:%s Loading acdb_loader_init_ACDB", dlerror());
117 }else {
118 acdb_init();
119 acdb_deallocate = (void (*)())::dlsym(mAcdbHandle,"acdb_loader_deallocate_ACDB");
120 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700121 }
122#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700123
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700124#ifdef QCOM_CSDCLIENT_ENABLED
125 mCsdHandle = ::dlopen("/system/lib/libcsd-client.so", RTLD_NOW);
126 if (mCsdHandle == NULL) {
127 ALOGE("AudioHardware: DLOPEN not successful for CSD CLIENT");
128 } else {
129 ALOGD("AudioHardware: DLOPEN successful for CSD CLIENT");
130 csd_start_playback = (int (*)())::dlsym(mCsdHandle,"csd_client_start_playback");
131 csd_stop_playback = (int (*)())::dlsym(mCsdHandle,"csd_client_stop_playback");
132 }
133 mALSADevice->setCsdHandle(mCsdHandle);
134#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700135 if((fp = fopen("/proc/asound/cards","r")) == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700136 ALOGE("Cannot open /proc/asound/cards file to get sound card info");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700137 } else {
138 while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700139 ALOGV("SoundCardInfo %s", soundCardInfo);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700140 if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
141 codec_rev = 1;
142 break;
143 } else if (strstr(soundCardInfo, "msm-snd-card")) {
144 codec_rev = 2;
145 break;
146 } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
147 codec_rev = 3;
148 break;
149 }
150 }
151 fclose(fp);
152 }
153
154 if (codec_rev == 1) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700155 ALOGV("Detected tabla 1.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700156 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
157 } else if (codec_rev == 3) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700158 ALOGV("Detected sitar 1.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700159 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
160 } else {
161 property_get("ro.board.platform", platform, "");
162 property_get("ro.baseband", baseband, "");
163 if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700164 ALOGV("Detected Fusion tabla 2.x");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700165 mFusion3Platform = true;
166 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
167 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700168 ALOGV("Detected tabla 2.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700169 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
170 }
171 }
172
173 if (mUcMgr < 0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700174 ALOGE("Failed to open ucm instance: %d", errno);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700175 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700176 ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700177 mUcMgr->acdb_handle = NULL;
178#ifdef QCOM_ACDB_ENABLED
179 if (mAcdbHandle) {
180 mUcMgr->acdb_handle = static_cast<void*> (mAcdbHandle);
181 }
182#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700183 }
184 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700185 ALOGE("ALSA Module could not be opened!!!");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700186 }
187 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700188 ALOGE("ALSA Module not found!!!");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700189 }
190}
191
192AudioHardwareALSA::~AudioHardwareALSA()
193{
194 if (mUcMgr != NULL) {
SathishKumar Mani9efed762012-09-18 18:52:48 -0700195 ALOGV("closing ucm instance: %u", (unsigned)mUcMgr);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700196 snd_use_case_mgr_close(mUcMgr);
197 }
198 if (mALSADevice) {
199 mALSADevice->common.close(&mALSADevice->common);
200 }
201 for(ALSAHandleList::iterator it = mDeviceList.begin();
202 it != mDeviceList.end(); ++it) {
203 it->useCase[0] = 0;
204 mDeviceList.erase(it);
205 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700206#ifdef QCOM_ACDB_ENABLED
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700207 if (acdb_deallocate == NULL) {
208 ALOGE("dlsym: Error:%s Loading acdb_deallocate_ACDB", dlerror());
209 } else {
210 acdb_deallocate();
211 }
212 if (mAcdbHandle) {
213 ::dlclose(mAcdbHandle);
214 mAcdbHandle = NULL;
215 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700216#endif
217#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700218 delete mAudioUsbALSA;
Ajay Dudani9746c472012-06-18 16:01:16 -0700219#endif
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700220
221#ifdef QCOM_CSDCLEINT_ENABLED
222 if (mCsdHandle) {
223 ::dlclose(mCsdHandle);
224 mCsdHandle = NULL;
225 }
226#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700227}
228
229status_t AudioHardwareALSA::initCheck()
230{
231 if (!mALSADevice)
232 return NO_INIT;
233
234 return NO_ERROR;
235}
236
237status_t AudioHardwareALSA::setVoiceVolume(float v)
238{
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700239 ALOGV("setVoiceVolume(%f)\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700240 if (v < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700241 ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700242 v = 0.0;
243 } else if (v > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700244 ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700245 v = 1.0;
246 }
247
248 int newMode = mode();
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700249 ALOGV("setVoiceVolume newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700250 int vol = lrint(v * 100.0);
251
252 // Voice volume levels from android are mapped to driver volume levels as follows.
253 // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
254 // So adjust the volume to get the correct volume index in driver
255 vol = 100 - vol;
256
257 if (mALSADevice) {
258 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
259 mALSADevice->setVoipVolume(vol);
260 } else if (newMode == AudioSystem::MODE_IN_CALL){
Ajay Dudani9746c472012-06-18 16:01:16 -0700261 if (mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700262 mALSADevice->setVoiceVolume(vol);
Ajay Dudani9746c472012-06-18 16:01:16 -0700263 if (mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700264 mALSADevice->setVoLTEVolume(vol);
265 }
266 }
267
268 return NO_ERROR;
269}
270
Ajay Dudani9746c472012-06-18 16:01:16 -0700271#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700272status_t AudioHardwareALSA::setFmVolume(float value)
273{
274 status_t status = NO_ERROR;
275
276 int vol;
277
278 if (value < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700279 ALOGW("setFmVolume(%f) under 0.0, assuming 0.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700280 value = 0.0;
281 } else if (value > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700282 ALOGW("setFmVolume(%f) over 1.0, assuming 1.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700283 value = 1.0;
284 }
285 vol = lrint((value * 0x2000) + 0.5);
286
SathishKumar Mani9efed762012-09-18 18:52:48 -0700287 ALOGV("setFmVolume(%f)\n", value);
288 ALOGV("Setting FM volume to %d (available range is 0 to 0x2000)\n", vol);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700289
290 mALSADevice->setFmVolume(vol);
291
292 return status;
293}
294#endif
295
296status_t AudioHardwareALSA::setMasterVolume(float volume)
297{
298 return NO_ERROR;
299}
300
301status_t AudioHardwareALSA::setMode(int mode)
302{
303 status_t status = NO_ERROR;
304
305 if (mode != mMode) {
306 status = AudioHardwareBase::setMode(mode);
307 }
308
309 if (mode == AudioSystem::MODE_IN_CALL) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700310 mCallState = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700311 }else if (mode == AudioSystem::MODE_NORMAL) {
312 mCallState = 0;
313 }
314
315 return status;
316}
317
318status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs)
319{
320 AudioParameter param = AudioParameter(keyValuePairs);
321 String8 key;
322 String8 value;
323 status_t status = NO_ERROR;
324 int device;
325 int btRate;
326 int state;
SathishKumar Mani9efed762012-09-18 18:52:48 -0700327 ALOGV("setParameters() %s", keyValuePairs.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700328
329 key = String8(TTY_MODE_KEY);
330 if (param.get(key, value) == NO_ERROR) {
331 mDevSettingsFlag &= TTY_CLEAR;
ty.leea97e6f62012-08-15 10:11:50 +0900332 if (value == "tty_full") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700333 mDevSettingsFlag |= TTY_FULL;
ty.leea97e6f62012-08-15 10:11:50 +0900334 } else if (value == "tty_hco") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700335 mDevSettingsFlag |= TTY_HCO;
ty.leea97e6f62012-08-15 10:11:50 +0900336 } else if (value == "tty_vco") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700337 mDevSettingsFlag |= TTY_VCO;
338 } else {
339 mDevSettingsFlag |= TTY_OFF;
340 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700341 ALOGI("Changed TTY Mode=%s", value.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700342 mALSADevice->setFlags(mDevSettingsFlag);
343 if(mMode != AudioSystem::MODE_IN_CALL){
344 return NO_ERROR;
345 }
346 doRouting(0);
347 }
348
349 key = String8(FLUENCE_KEY);
350 if (param.get(key, value) == NO_ERROR) {
351 if (value == "quadmic") {
352 mDevSettingsFlag |= QMIC_FLAG;
353 mDevSettingsFlag &= (~DMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700354 ALOGV("Fluence quadMic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700355 } else if (value == "dualmic") {
356 mDevSettingsFlag |= DMIC_FLAG;
357 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700358 ALOGV("Fluence dualmic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700359 } else if (value == "none") {
360 mDevSettingsFlag &= (~DMIC_FLAG);
361 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700362 ALOGV("Fluence feature Disabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700363 }
364 mALSADevice->setFlags(mDevSettingsFlag);
365 doRouting(0);
366 }
367
Ajay Dudani9746c472012-06-18 16:01:16 -0700368#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700369 if (mFusion3Platform) {
370 key = String8(INCALLMUSIC_KEY);
371 if (param.get(key, value) == NO_ERROR) {
372 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700373 ALOGV("Enabling Incall Music setting in the setparameter\n");
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700374 if (csd_start_playback == NULL) {
375 ALOGE("dlsym: Error:%s Loading csd_client_start_playback", dlerror());
376 } else {
377 csd_start_playback();
378 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700379 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700380 ALOGV("Disabling Incall Music setting in the setparameter\n");
SathishKumar Mani5ff7a022012-09-14 11:36:35 -0700381 if (csd_stop_playback == NULL) {
382 ALOGE("dlsym: Error:%s Loading csd_client_stop_playback", dlerror());
383 } else {
384 csd_stop_playback();
385 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700386 }
387 }
388 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700389#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700390
391 key = String8(ANC_KEY);
392 if (param.get(key, value) == NO_ERROR) {
393 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700394 ALOGV("Enabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700395 mDevSettingsFlag |= ANC_FLAG;
396 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700397 ALOGV("Disabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700398 mDevSettingsFlag &= (~ANC_FLAG);
399 }
400 mALSADevice->setFlags(mDevSettingsFlag);
401 doRouting(0);
402 }
403
404 key = String8(AudioParameter::keyRouting);
405 if (param.getInt(key, device) == NO_ERROR) {
406 // Ignore routing if device is 0.
407 if(device) {
408 doRouting(device);
409 }
410 param.remove(key);
411 }
412
413 key = String8(BT_SAMPLERATE_KEY);
414 if (param.getInt(key, btRate) == NO_ERROR) {
415 mALSADevice->setBtscoRate(btRate);
416 param.remove(key);
417 }
418
419 key = String8(BTHEADSET_VGS);
420 if (param.get(key, value) == NO_ERROR) {
421 if (value == "on") {
422 mBluetoothVGS = true;
423 } else {
424 mBluetoothVGS = false;
425 }
426 }
427
428 key = String8(WIDEVOICE_KEY);
429 if (param.get(key, value) == NO_ERROR) {
430 bool flag = false;
431 if (value == "true") {
432 flag = true;
433 }
434 if(mALSADevice) {
435 mALSADevice->enableWideVoice(flag);
436 }
437 param.remove(key);
438 }
439
440 key = String8(VOIPRATE_KEY);
441 if (param.get(key, value) == NO_ERROR) {
442 mVoipBitRate = atoi(value);
443 param.remove(key);
444 }
445
446 key = String8(FENS_KEY);
447 if (param.get(key, value) == NO_ERROR) {
448 bool flag = false;
449 if (value == "true") {
450 flag = true;
451 }
452 if(mALSADevice) {
453 mALSADevice->enableFENS(flag);
454 }
455 param.remove(key);
456 }
457
Ajay Dudani9746c472012-06-18 16:01:16 -0700458#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700459 key = String8(AudioParameter::keyHandleFm);
460 if (param.getInt(key, device) == NO_ERROR) {
461 // Ignore if device is 0
462 if(device) {
463 handleFm(device);
464 }
465 param.remove(key);
466 }
467#endif
468
469 key = String8(ST_KEY);
470 if (param.get(key, value) == NO_ERROR) {
471 bool flag = false;
472 if (value == "true") {
473 flag = true;
474 }
475 if(mALSADevice) {
476 mALSADevice->enableSlowTalk(flag);
477 }
478 param.remove(key);
479 }
480 key = String8(MODE_CALL_KEY);
481 if (param.getInt(key,state) == NO_ERROR) {
482 if (mCallState != state) {
483 mCallState = state;
484 doRouting(0);
485 }
486 mCallState = state;
487 }
488 if (param.size()) {
489 status = BAD_VALUE;
490 }
491 return status;
492}
493
494String8 AudioHardwareALSA::getParameters(const String8& keys)
495{
496 AudioParameter param = AudioParameter(keys);
497 String8 value;
498
499 String8 key = String8(DUALMIC_KEY);
500 if (param.get(key, value) == NO_ERROR) {
501 value = String8("false");
502 param.add(key, value);
503 }
504
505 key = String8(FLUENCE_KEY);
506 if (param.get(key, value) == NO_ERROR) {
507 if ((mDevSettingsFlag & QMIC_FLAG) &&
508 (mDevSettingsFlag & ~DMIC_FLAG))
509 value = String8("quadmic");
510 else if ((mDevSettingsFlag & DMIC_FLAG) &&
511 (mDevSettingsFlag & ~QMIC_FLAG))
512 value = String8("dualmic");
513 else if ((mDevSettingsFlag & ~DMIC_FLAG) &&
514 (mDevSettingsFlag & ~QMIC_FLAG))
515 value = String8("none");
516 param.add(key, value);
517 }
518
Ajay Dudani9746c472012-06-18 16:01:16 -0700519#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700520 key = String8("Fm-radio");
521 if ( param.get(key,value) == NO_ERROR ) {
522 if ( mIsFmActive ) {
523 param.addInt(String8("isFMON"), true );
524 }
525 }
526#endif
527
528 key = String8(BTHEADSET_VGS);
529 if (param.get(key, value) == NO_ERROR) {
530 if(mBluetoothVGS)
531 param.addInt(String8("isVGS"), true);
532 }
533
Iliyan Malchev4113f342012-06-11 14:39:47 -0700534 ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700535 return param.toString();
536}
537
Ajay Dudani9746c472012-06-18 16:01:16 -0700538#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700539void AudioHardwareALSA::closeUSBPlayback()
540{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700541 ALOGV("closeUSBPlayback, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700542 musbPlaybackState = 0;
543 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_KILLTHREAD);
544}
545
546void AudioHardwareALSA::closeUSBRecording()
547{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700548 ALOGV("closeUSBRecording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700549 musbRecordingState = 0;
550 mAudioUsbALSA->exitRecordingThread(SIGNAL_EVENT_KILLTHREAD);
551}
552
553void AudioHardwareALSA::closeUsbPlaybackIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700554 ALOGV("closeUsbPlaybackIfNothingActive, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700555 if(!musbPlaybackState && mAudioUsbALSA != NULL) {
556 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_TIMEOUT);
557 }
558}
559
560void AudioHardwareALSA::closeUsbRecordingIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700561 ALOGV("closeUsbRecordingIfNothingActive, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700562 if(!musbRecordingState && mAudioUsbALSA != NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700563 ALOGD("Closing USB Recording Session as no stream is active");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700564 mAudioUsbALSA->setkillUsbRecordingThread(true);
565 }
566}
567
568void AudioHardwareALSA::startUsbPlaybackIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700569 ALOGV("Starting the USB playback %d kill %d", musbPlaybackState,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700570 mAudioUsbALSA->getkillUsbPlaybackThread());
571 if((!musbPlaybackState) || (mAudioUsbALSA->getkillUsbPlaybackThread() == true)) {
572 mAudioUsbALSA->startPlayback();
573 }
574}
575
576void AudioHardwareALSA::startUsbRecordingIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700577 ALOGV("Starting the recording musbRecordingState: %d killUsbRecordingThread %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700578 musbRecordingState, mAudioUsbALSA->getkillUsbRecordingThread());
579 if((!musbRecordingState) || (mAudioUsbALSA->getkillUsbRecordingThread() == true)) {
580 mAudioUsbALSA->startRecording();
581 }
582}
Ajay Dudani9746c472012-06-18 16:01:16 -0700583#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700584
585void AudioHardwareALSA::doRouting(int device)
586{
587 Mutex::Autolock autoLock(mLock);
588 int newMode = mode();
589 bool isRouted = false;
590
Ajay Dudani9746c472012-06-18 16:01:16 -0700591 if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
592#ifdef QCOM_FM_ENABLED
593 || (device == AudioSystem::DEVICE_IN_FM_RX)
594 || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT)
595 || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700596#endif
Ajay Dudani9746c472012-06-18 16:01:16 -0700597 || (device == AudioSystem::DEVICE_IN_COMMUNICATION)
598 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700599 ALOGV("Ignoring routing for FM/INCALL/VOIP recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700600 return;
601 }
602 if (device == 0)
603 device = mCurDevice;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700604 ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
Iliyan Malchev4765c432012-06-11 14:36:16 -0700605 "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
606 mIsFmActive);
607
608 isRouted = routeVoLTECall(device, newMode);
609 isRouted |= routeVoiceCall(device, newMode);
610
611 if(!isRouted) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700612#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700613 if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
614 !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
615 !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
616 (musbPlaybackState)){
617 //USB unplugged
618 device &= ~ AudioSystem::DEVICE_OUT_PROXY;
619 device &= ~ AudioSystem::DEVICE_IN_PROXY;
620 ALSAHandleList::iterator it = mDeviceList.end();
621 it--;
622 mALSADevice->route(&(*it), (uint32_t)device, newMode);
SathishKumar Mani0a019912012-09-11 12:33:11 -0700623 ALOGD("USB UNPLUGGED, setting musbPlaybackState to 0");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700624 musbPlaybackState = 0;
625 musbRecordingState = 0;
626 closeUSBRecording();
627 closeUSBPlayback();
628 } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
629 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
SathishKumar Mani0a019912012-09-11 12:33:11 -0700630 ALOGD("Routing everything to prox now");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700631 ALSAHandleList::iterator it = mDeviceList.end();
632 it--;
633 mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
634 newMode);
635 for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
636 if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
637 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700638 ALOGV("doRouting: LPA device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700639 startUsbPlaybackIfNotStarted();
640 musbPlaybackState |= USBPLAYBACKBIT_LPA;
641 break;
642 } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
643 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700644 ALOGV("doRouting: VOICE device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700645 startUsbRecordingIfNotStarted();
646 startUsbPlaybackIfNotStarted();
647 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
648 musbRecordingState |= USBPLAYBACKBIT_VOICECALL;
649 break;
650 }else if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
651 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700652 ALOGV("doRouting: FM device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700653 startUsbPlaybackIfNotStarted();
654 musbPlaybackState |= USBPLAYBACKBIT_FM;
655 break;
656 }
657 }
SathishKumar Manie42406e2012-08-29 16:25:54 -0700658 } else
Iliyan Malchev4765c432012-06-11 14:36:16 -0700659#endif
SathishKumar Manie42406e2012-08-29 16:25:54 -0700660 {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700661 ALSAHandleList::iterator it = mDeviceList.end();
662 it--;
663 mALSADevice->route(&(*it), (uint32_t)device, newMode);
664 }
665 }
666 mCurDevice = device;
667}
668
669uint32_t AudioHardwareALSA::getVoipMode(int format)
670{
671 switch(format) {
672 case AudioSystem::PCM_16_BIT:
673 return MODE_PCM;
674 break;
675 case AudioSystem::AMR_NB:
676 return MODE_AMR;
677 break;
678 case AudioSystem::AMR_WB:
679 return MODE_AMR_WB;
680 break;
681
Ajay Dudani9746c472012-06-18 16:01:16 -0700682#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700683 case AudioSystem::EVRC:
684 return MODE_IS127;
685 break;
686
687 case AudioSystem::EVRCB:
688 return MODE_4GV_NB;
689 break;
690 case AudioSystem::EVRCWB:
691 return MODE_4GV_WB;
692 break;
Ajay Dudani9746c472012-06-18 16:01:16 -0700693#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700694
695 default:
696 return MODE_PCM;
697 }
698}
699
700AudioStreamOut *
701AudioHardwareALSA::openOutputStream(uint32_t devices,
702 int *format,
703 uint32_t *channels,
704 uint32_t *sampleRate,
705 status_t *status)
706{
707 Mutex::Autolock autoLock(mLock);
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700708 ALOGV("openOutputStream: devices 0x%x channels %d sampleRate %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700709 devices, *channels, *sampleRate);
710
SathishKumar Mani88613382012-08-13 18:40:18 -0700711 audio_output_flags_t flag = static_cast<audio_output_flags_t> (*status);
712
Iliyan Malchev4765c432012-06-11 14:36:16 -0700713 status_t err = BAD_VALUE;
SathishKumar Mani88613382012-08-13 18:40:18 -0700714 *status = NO_ERROR;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700715 AudioStreamOutALSA *out = 0;
716 ALSAHandleList::iterator it;
717
718 if (devices & (devices - 1)) {
719 if (status) *status = err;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700720 ALOGE("openOutputStream called with bad devices");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700721 return out;
722 }
SathishKumar Mani88613382012-08-13 18:40:18 -0700723
724
Iliyan Malchev4765c432012-06-11 14:36:16 -0700725# if 0
726 if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
727 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
728 bool voipstream_active = false;
729 for(it = mDeviceList.begin();
730 it != mDeviceList.end(); ++it) {
731 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
732 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700733 ALOGD("openOutput: it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700734 voipstream_active = true;
735 break;
736 }
737 }
738 if(voipstream_active == false) {
739 mVoipStreamCount = 0;
740 mVoipMicMute = false;
741 alsa_handle_t alsa_handle;
742 unsigned long bufferSize;
743 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
744 bufferSize = VOIP_BUFFER_SIZE_8K;
745 }
746 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
747 bufferSize = VOIP_BUFFER_SIZE_16K;
748 }
749 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700750 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700751 if (status) *status = err;
752 return out;
753 }
754 alsa_handle.module = mALSADevice;
755 alsa_handle.bufferSize = bufferSize;
756 alsa_handle.devices = devices;
757 alsa_handle.handle = 0;
758 if(*format == AudioSystem::PCM_16_BIT)
759 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
760 else
761 alsa_handle.format = *format;
762 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
763 alsa_handle.sampleRate = *sampleRate;
764 alsa_handle.latency = VOIP_PLAYBACK_LATENCY;
765 alsa_handle.rxHandle = 0;
766 alsa_handle.ucMgr = mUcMgr;
767 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
768 char *use_case;
769 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
770 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
771 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
772 } else {
773 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
774 }
775 free(use_case);
776 mDeviceList.push_back(alsa_handle);
777 it = mDeviceList.end();
778 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700779 ALOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipStreamCount %d mode %d", it->useCase,mCurDevice,mVoipStreamCount, mode());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700780 if((mCurDevice & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
781 (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
782 (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700783 ALOGD("Routing to proxy for normal voip call in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700784 mCurDevice |= AudioSystem::DEVICE_OUT_PROXY;
785 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
786 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700787 ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700788 startUsbPlaybackIfNotStarted();
789 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700790 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700791 startUsbRecordingIfNotStarted();
792 musbRecordingState |= USBRECBIT_VOIPCALL;
793 } else{
794 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
795 }
796 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
797 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
798 } else {
799 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
800 }
801 err = mALSADevice->startVoipCall(&(*it));
802 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700803 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700804 return NULL;
805 }
806 }
807 out = new AudioStreamOutALSA(this, &(*it));
808 err = out->set(format, channels, sampleRate, devices);
809 if(err == NO_ERROR) {
810 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -0700811 ALOGD("openoutput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700812 }
813 if (status) *status = err;
814 return out;
815 } else
816#endif
817 {
818
819 alsa_handle_t alsa_handle;
820 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
821
822 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
823 bufferSize &= ~b;
824
825 alsa_handle.module = mALSADevice;
826 alsa_handle.bufferSize = bufferSize;
827 alsa_handle.devices = devices;
828 alsa_handle.handle = 0;
829 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
830 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
831 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
832 alsa_handle.latency = PLAYBACK_LATENCY;
833 alsa_handle.rxHandle = 0;
834 alsa_handle.ucMgr = mUcMgr;
SathishKumar Mani88613382012-08-13 18:40:18 -0700835 alsa_handle.isDeepbufferOutput = false;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700836
837 char *use_case;
838 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
SathishKumar Mani88613382012-08-13 18:40:18 -0700839
840 if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
SathishKumar Mani9efed762012-09-18 18:52:48 -0700841 ALOGD("openOutputStream: DeepBuffer Output");
SathishKumar Mani88613382012-08-13 18:40:18 -0700842 alsa_handle.isDeepbufferOutput = true;
843 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
844 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
845 } else {
846 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
847 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700848 } else {
SathishKumar Mani9efed762012-09-18 18:52:48 -0700849 ALOGD("openOutputStream: Lowlatency Output");
SathishKumar Mani88613382012-08-13 18:40:18 -0700850 alsa_handle.bufferSize = PLAYBACK_LOW_LATENCY_BUFFER_SIZE;
851 alsa_handle.latency = PLAYBACK_LOW_LATENCY;
852 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
853 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
854 } else {
855 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
856 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700857 }
858 free(use_case);
859 mDeviceList.push_back(alsa_handle);
860 ALSAHandleList::iterator it = mDeviceList.end();
861 it--;
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700862 ALOGV("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700863#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700864 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
865 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
SathishKumar Mani0a019912012-09-11 12:33:11 -0700866 ALOGD("Routing to proxy for normal playback in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700867 devices |= AudioSystem::DEVICE_OUT_PROXY;
868 }
869#endif
870 mALSADevice->route(&(*it), devices, mode());
SathishKumar Mani88613382012-08-13 18:40:18 -0700871 if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
872 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
873 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
874 } else {
875 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
876 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700877 } else {
SathishKumar Mani88613382012-08-13 18:40:18 -0700878 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
879 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC);
880 } else {
881 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC);
882 }
Iliyan Malchev4765c432012-06-11 14:36:16 -0700883 }
884 err = mALSADevice->open(&(*it));
885 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700886 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700887 } else {
888 out = new AudioStreamOutALSA(this, &(*it));
889 err = out->set(format, channels, sampleRate, devices);
890 }
891
892 if (status) *status = err;
893 return out;
894 }
895}
896
897void
898AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
899{
900 delete out;
901}
902
Ajay Dudani9746c472012-06-18 16:01:16 -0700903#ifdef QCOM_TUNNEL_LPA_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700904AudioStreamOut *
905AudioHardwareALSA::openOutputSession(uint32_t devices,
906 int *format,
907 status_t *status,
908 int sessionId,
909 uint32_t samplingRate,
910 uint32_t channels)
911{
912 Mutex::Autolock autoLock(mLock);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700913 ALOGD("openOutputSession = %d" ,sessionId);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700914 AudioStreamOutALSA *out = 0;
915 status_t err = BAD_VALUE;
916
917 alsa_handle_t alsa_handle;
918 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
919
920 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
921 bufferSize &= ~b;
922
923 alsa_handle.module = mALSADevice;
924 alsa_handle.bufferSize = bufferSize;
925 alsa_handle.devices = devices;
926 alsa_handle.handle = 0;
927 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
928 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
929 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
930 alsa_handle.latency = VOICE_LATENCY;
931 alsa_handle.rxHandle = 0;
932 alsa_handle.ucMgr = mUcMgr;
933
934 char *use_case;
935 if(sessionId == TUNNEL_SESSION_ID) {
936 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
937 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
938 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, sizeof(alsa_handle.useCase));
939 } else {
940 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, sizeof(alsa_handle.useCase));
941 }
942 } else {
943 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
944 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
945 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, sizeof(alsa_handle.useCase));
946 } else {
947 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LPA, sizeof(alsa_handle.useCase));
948 }
949 }
950 free(use_case);
951 mDeviceList.push_back(alsa_handle);
952 ALSAHandleList::iterator it = mDeviceList.end();
953 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700954 ALOGD("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700955#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700956 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
957 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
SathishKumar Mani0a019912012-09-11 12:33:11 -0700958 ALOGD("Routing to proxy for LPA in openOutputSession");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700959 devices |= AudioSystem::DEVICE_OUT_PROXY;
960 mALSADevice->route(&(*it), devices, mode());
961 devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700962 ALOGD("Starting USBPlayback for LPA");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700963 startUsbPlaybackIfNotStarted();
964 musbPlaybackState |= USBPLAYBACKBIT_LPA;
965 } else
966#endif
967 {
968 mALSADevice->route(&(*it), devices, mode());
969 }
970 if(sessionId == TUNNEL_SESSION_ID) {
971 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) {
972 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_TUNNEL);
973 } else {
974 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_TUNNEL);
975 }
976 }
977 else {
978 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) {
979 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOW_POWER);
980 } else {
981 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LPA);
982 }
983 }
984 err = mALSADevice->open(&(*it));
985 out = new AudioStreamOutALSA(this, &(*it));
986
987 if (status) *status = err;
988 return out;
989}
990
991void
992AudioHardwareALSA::closeOutputSession(AudioStreamOut* out)
993{
994 delete out;
995}
Ajay Dudani9746c472012-06-18 16:01:16 -0700996#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700997
998AudioStreamIn *
999AudioHardwareALSA::openInputStream(uint32_t devices,
1000 int *format,
1001 uint32_t *channels,
1002 uint32_t *sampleRate,
1003 status_t *status,
1004 AudioSystem::audio_in_acoustics acoustics)
1005{
1006 Mutex::Autolock autoLock(mLock);
1007 char *use_case;
1008 int newMode = mode();
1009 uint32_t route_devices;
1010
1011 status_t err = BAD_VALUE;
1012 AudioStreamInALSA *in = 0;
1013 ALSAHandleList::iterator it;
1014
Iliyan Malchev4113f342012-06-11 14:39:47 -07001015 ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001016 if (devices & (devices - 1)) {
1017 if (status) *status = err;
1018 return in;
1019 }
1020
1021 if((devices == AudioSystem::DEVICE_IN_COMMUNICATION) &&
1022 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
1023 bool voipstream_active = false;
1024 for(it = mDeviceList.begin();
1025 it != mDeviceList.end(); ++it) {
1026 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
1027 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001028 ALOGD("openInput: it->rxHandle %p it->handle %p",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001029 voipstream_active = true;
1030 break;
1031 }
1032 }
1033 if(voipstream_active == false) {
1034 mVoipStreamCount = 0;
1035 mVoipMicMute = false;
1036 alsa_handle_t alsa_handle;
1037 unsigned long bufferSize;
1038 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
1039 bufferSize = VOIP_BUFFER_SIZE_8K;
1040 }
1041 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
1042 bufferSize = VOIP_BUFFER_SIZE_16K;
1043 }
1044 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001045 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001046 if (status) *status = err;
1047 return in;
1048 }
1049 alsa_handle.module = mALSADevice;
1050 alsa_handle.bufferSize = bufferSize;
1051 alsa_handle.devices = devices;
1052 alsa_handle.handle = 0;
1053 if(*format == AudioSystem::PCM_16_BIT)
1054 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1055 else
1056 alsa_handle.format = *format;
1057 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
1058 alsa_handle.sampleRate = *sampleRate;
1059 alsa_handle.latency = VOIP_RECORD_LATENCY;
1060 alsa_handle.rxHandle = 0;
1061 alsa_handle.ucMgr = mUcMgr;
1062 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
1063 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1064 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1065 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
1066 } else {
1067 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
1068 }
1069 free(use_case);
1070 mDeviceList.push_back(alsa_handle);
1071 it = mDeviceList.end();
1072 it--;
SathishKumar Mani0a019912012-09-11 12:33:11 -07001073 ALOGD("mCurrDevice: %d", mCurDevice);
Ajay Dudani9746c472012-06-18 16:01:16 -07001074#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001075 if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1076 (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
SathishKumar Mani0a019912012-09-11 12:33:11 -07001077 ALOGD("Routing everything from proxy for voipcall");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001078 mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -07001079 ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001080 startUsbPlaybackIfNotStarted();
1081 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001082 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001083 startUsbRecordingIfNotStarted();
1084 musbRecordingState |= USBRECBIT_VOIPCALL;
SathishKumar Manie42406e2012-08-29 16:25:54 -07001085 } else
Iliyan Malchev4765c432012-06-11 14:36:16 -07001086#endif
1087 {
1088 mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
1089 }
1090 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
1091 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
1092 } else {
1093 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
1094 }
1095 if(sampleRate) {
1096 it->sampleRate = *sampleRate;
1097 }
1098 if(channels)
1099 it->channels = AudioSystem::popCount(*channels);
1100 err = mALSADevice->startVoipCall(&(*it));
1101 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001102 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001103 return NULL;
1104 }
1105 }
1106 in = new AudioStreamInALSA(this, &(*it), acoustics);
1107 err = in->set(format, channels, sampleRate, devices);
1108 if(err == NO_ERROR) {
1109 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -07001110 ALOGD("OpenInput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001111 }
SathishKumar Mani0a019912012-09-11 12:33:11 -07001112 ALOGD("openInput: After Get alsahandle");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001113 if (status) *status = err;
1114 return in;
1115 } else
1116 {
1117 for(ALSAHandleList::iterator itDev = mDeviceList.begin();
1118 itDev != mDeviceList.end(); ++itDev)
1119 {
1120 if((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_HIFI_REC, MAX_UC_LEN))
1121 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, MAX_UC_LEN))
SathishKumar Mani88613382012-08-13 18:40:18 -07001122 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, MAX_UC_LEN))
1123 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, MAX_UC_LEN))
Iliyan Malchev4765c432012-06-11 14:36:16 -07001124 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_FM, MAX_UC_LEN))
Ajay Dudani9746c472012-06-18 16:01:16 -07001125#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001126 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_REC, MAX_UC_LEN))
1127#endif
1128 )
1129 {
Ajay Dudani9746c472012-06-18 16:01:16 -07001130#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001131 if(!(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001132 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001133 itDev->useCase, itDev->devices, itDev->module);
1134 return in;
1135 }
1136#endif
1137 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001138#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001139 else if ((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, MAX_UC_LEN))
1140 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, MAX_UC_LEN)))
1141 {
1142 if((devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001143 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001144 itDev->useCase, itDev->devices, itDev->module);
1145 return in;
1146 }
1147 }
1148#endif
1149 }
1150
1151 alsa_handle_t alsa_handle;
1152 unsigned long bufferSize = DEFAULT_IN_BUFFER_SIZE;
1153
1154 alsa_handle.module = mALSADevice;
1155 alsa_handle.bufferSize = bufferSize;
1156 alsa_handle.devices = devices;
1157 alsa_handle.handle = 0;
1158 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1159 alsa_handle.channels = VOICE_CHANNEL_MODE;
1160 alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
1161 alsa_handle.latency = RECORD_LATENCY;
1162 alsa_handle.rxHandle = 0;
1163 alsa_handle.ucMgr = mUcMgr;
1164 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1165 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1166 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1167 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001168 ALOGD("openInputStream: into incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001169 mIncallMode = *channels;
1170 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1171 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1172 if (mFusion3Platform) {
1173 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1174 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1175 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001176 } else {
1177 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
1178 sizeof(alsa_handle.useCase));
1179 }
1180 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1181 if (mFusion3Platform) {
1182 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1183 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1184 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001185 } else {
1186 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
1187 sizeof(alsa_handle.useCase));
1188 }
1189 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001190#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001191 } else if((devices == AudioSystem::DEVICE_IN_FM_RX)) {
1192 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(alsa_handle.useCase));
1193 } else if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1194 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
1195#endif
1196 } else {
SathishKumar Mani9efed762012-09-18 18:52:48 -07001197 char value[128];
1198 property_get("persist.audio.lowlatency.rec",value,"0");
SathishKumar Mani88613382012-08-13 18:40:18 -07001199 if (!strcmp("true", value)) {
1200 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
1201 } else {
1202 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(alsa_handle.useCase));
1203 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001204 }
1205 } else {
1206 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1207 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001208 ALOGD("openInputStream: incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001209 mIncallMode = *channels;
1210 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1211 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1212 if (mFusion3Platform) {
1213 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1214 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1215 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001216 } else {
1217 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
1218 sizeof(alsa_handle.useCase));
1219 }
1220 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1221 if (mFusion3Platform) {
1222 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1223 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1224 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001225 } else {
1226 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
1227 sizeof(alsa_handle.useCase));
1228 }
1229 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001230#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001231 } else if(devices == AudioSystem::DEVICE_IN_FM_RX) {
1232 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_REC, sizeof(alsa_handle.useCase));
1233 } else if (devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1234 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(alsa_handle.useCase));
1235#endif
1236 } else {
SathishKumar Mani88613382012-08-13 18:40:18 -07001237 char value[128];
1238 property_get("persist.audio.lowlatency.rec",value,"0");
1239 if (!strcmp("true", value)) {
1240 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(alsa_handle.useCase));
1241 } else {
1242 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
1243 }
Iliyan Malchev4765c432012-06-11 14:36:16 -07001244 }
1245 }
1246 free(use_case);
1247 mDeviceList.push_back(alsa_handle);
1248 ALSAHandleList::iterator it = mDeviceList.end();
1249 it--;
1250 //update channel info before do routing
1251 if(channels) {
1252 it->channels = AudioSystem::popCount((*channels) &
Ajay Dudani9746c472012-06-18 16:01:16 -07001253 (AudioSystem::CHANNEL_IN_STEREO
1254 | AudioSystem::CHANNEL_IN_MONO
1255#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001256 | AudioSystem::CHANNEL_IN_5POINT1
1257#endif
1258 ));
Iliyan Malchev4113f342012-06-11 14:39:47 -07001259 ALOGV("updated channel info: channels=%d", it->channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001260 }
1261 if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
1262 /* Add current devices info to devices to do route */
Ajay Dudani9746c472012-06-18 16:01:16 -07001263#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001264 if(mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
1265 mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001266 ALOGD("Routing everything from proxy for VOIP call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001267 route_devices = devices | AudioSystem::DEVICE_IN_PROXY;
1268 } else
1269#endif
1270 {
1271 route_devices = devices | mCurDevice;
1272 }
1273 mALSADevice->route(&(*it), route_devices, mode());
1274 } else {
Ajay Dudani9746c472012-06-18 16:01:16 -07001275#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001276 if(devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET ||
1277 devices & AudioSystem::DEVICE_IN_PROXY) {
1278 devices |= AudioSystem::DEVICE_IN_PROXY;
SathishKumar Mani0a019912012-09-11 12:33:11 -07001279 ALOGD("routing everything from proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001280 mALSADevice->route(&(*it), devices, mode());
1281 } else
1282#endif
1283 {
1284 mALSADevice->route(&(*it), devices, mode());
1285 }
1286 }
1287
1288 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
SathishKumar Mani88613382012-08-13 18:40:18 -07001289 !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) ||
Ajay Dudani9746c472012-06-18 16:01:16 -07001290#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001291 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) ||
1292 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
1293#endif
1294 !strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) ||
1295 !strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
1296 !strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
1297 snd_use_case_set(mUcMgr, "_verb", it->useCase);
1298 } else {
1299 snd_use_case_set(mUcMgr, "_enamod", it->useCase);
1300 }
1301 if(sampleRate) {
1302 it->sampleRate = *sampleRate;
1303 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001304#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001305 if (6 == it->channels) {
1306 if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
1307 || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001308 ALOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001309 it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
1310 }
1311 }
1312#endif
1313 err = mALSADevice->open(&(*it));
1314 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001315 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001316 } else {
1317 in = new AudioStreamInALSA(this, &(*it), acoustics);
1318 err = in->set(format, channels, sampleRate, devices);
1319 }
1320 if (status) *status = err;
1321 return in;
1322 }
1323}
1324
1325void
1326AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
1327{
1328 delete in;
1329}
1330
1331status_t AudioHardwareALSA::setMicMute(bool state)
1332{
1333 int newMode = mode();
Iliyan Malchev4113f342012-06-11 14:39:47 -07001334 ALOGD("setMicMute newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001335 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1336 if (mVoipMicMute != state) {
1337 mVoipMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001338 ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001339 if(mALSADevice) {
1340 mALSADevice->setVoipMicMute(state);
1341 }
1342 }
1343 } else {
1344 if (mMicMute != state) {
1345 mMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001346 ALOGD("setMicMute: mMicMute %d", mMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001347 if(mALSADevice) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001348 if(mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001349 mALSADevice->setMicMute(state);
Ajay Dudani9746c472012-06-18 16:01:16 -07001350 if(mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001351 mALSADevice->setVoLTEMicMute(state);
1352 }
1353 }
1354 }
1355 return NO_ERROR;
1356}
1357
1358status_t AudioHardwareALSA::getMicMute(bool *state)
1359{
1360 int newMode = mode();
1361 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1362 *state = mVoipMicMute;
1363 } else {
1364 *state = mMicMute;
1365 }
1366 return NO_ERROR;
1367}
1368
1369status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
1370{
1371 return NO_ERROR;
1372}
1373
1374size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
1375{
1376 size_t bufferSize;
1377 if (format != AudioSystem::PCM_16_BIT
1378 && format != AudioSystem::AMR_NB
1379 && format != AudioSystem::AMR_WB
Ajay Dudani9746c472012-06-18 16:01:16 -07001380#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001381 && format != AudioSystem::EVRC
1382 && format != AudioSystem::EVRCB
Ajay Dudani9746c472012-06-18 16:01:16 -07001383 && format != AudioSystem::EVRCWB
1384#endif
1385 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001386 ALOGW("getInputBufferSize bad format: %d", format);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001387 return 0;
1388 }
1389 if(sampleRate == 16000) {
1390 bufferSize = DEFAULT_IN_BUFFER_SIZE * 2 * channelCount;
1391 } else if(sampleRate < 44100) {
1392 bufferSize = DEFAULT_IN_BUFFER_SIZE * channelCount;
1393 } else {
1394 bufferSize = DEFAULT_IN_BUFFER_SIZE * 12;
1395 }
1396 return bufferSize;
1397}
1398
Ajay Dudani9746c472012-06-18 16:01:16 -07001399#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001400void AudioHardwareALSA::handleFm(int device)
1401{
1402int newMode = mode();
1403 if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
1404 // Start FM Radio on current active device
1405 unsigned long bufferSize = FM_BUFFER_SIZE;
1406 alsa_handle_t alsa_handle;
1407 char *use_case;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001408 ALOGV("Start FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001409 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1410 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1411 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, sizeof(alsa_handle.useCase));
1412 } else {
1413 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_FM, sizeof(alsa_handle.useCase));
1414 }
1415 free(use_case);
1416
1417 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1418 bufferSize &= ~b;
1419 alsa_handle.module = mALSADevice;
1420 alsa_handle.bufferSize = bufferSize;
1421 alsa_handle.devices = device;
1422 alsa_handle.handle = 0;
1423 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1424 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
1425 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
1426 alsa_handle.latency = VOICE_LATENCY;
1427 alsa_handle.rxHandle = 0;
1428 alsa_handle.ucMgr = mUcMgr;
1429 mIsFmActive = 1;
1430 mDeviceList.push_back(alsa_handle);
1431 ALSAHandleList::iterator it = mDeviceList.end();
1432 it--;
1433 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1434 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1435 device |= AudioSystem::DEVICE_OUT_PROXY;
1436 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
SathishKumar Mani0a019912012-09-11 12:33:11 -07001437 ALOGD("Routing to proxy for FM case");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001438 }
1439 mALSADevice->route(&(*it), (uint32_t)device, newMode);
1440 if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) {
1441 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_DIGITAL_RADIO);
1442 } else {
1443 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
1444 }
1445 mALSADevice->startFm(&(*it));
1446 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1447 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
SathishKumar Mani0a019912012-09-11 12:33:11 -07001448 ALOGD("Starting FM, musbPlaybackState %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001449 startUsbPlaybackIfNotStarted();
1450 musbPlaybackState |= USBPLAYBACKBIT_FM;
1451 }
1452 } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
1453 //i Stop FM Radio
Iliyan Malchev4113f342012-06-11 14:39:47 -07001454 ALOGV("Stop FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001455 for(ALSAHandleList::iterator it = mDeviceList.begin();
1456 it != mDeviceList.end(); ++it) {
1457 if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
1458 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
1459 mALSADevice->close(&(*it));
1460 //mALSADevice->route(&(*it), (uint32_t)device, newMode);
1461 mDeviceList.erase(it);
1462 break;
1463 }
1464 }
1465 mIsFmActive = 0;
1466 musbPlaybackState &= ~USBPLAYBACKBIT_FM;
1467 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1468 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1469 closeUsbPlaybackIfNothingActive();
1470 }
1471 }
1472}
1473#endif
1474
1475void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, int device)
1476{
1477 for(ALSAHandleList::iterator it = mDeviceList.begin();
1478 it != mDeviceList.end(); ++it) {
1479 if((!strcmp(it->useCase, verb)) ||
1480 (!strcmp(it->useCase, modifier))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001481 ALOGV("Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001482 mALSADevice->close(&(*it));
1483 mALSADevice->route(&(*it), (uint32_t)device, mode);
1484 mDeviceList.erase(it);
1485 break;
1486 }
1487 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001488#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001489 if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
SathishKumar Mani0a019912012-09-11 12:33:11 -07001490 ALOGD("Voice call ended on USB");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001491 musbPlaybackState &= ~USBPLAYBACKBIT_VOICECALL;
1492 musbRecordingState &= ~USBRECBIT_VOICECALL;
1493 closeUsbRecordingIfNothingActive();
1494 closeUsbPlaybackIfNothingActive();
1495 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001496#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001497}
1498void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, int device)
1499{
1500// Start voice call
SathishKumar Mani018d1c52012-09-11 14:58:18 -07001501unsigned long bufferSize = DEFAULT_VOICE_BUFFER_SIZE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001502alsa_handle_t alsa_handle;
1503char *use_case;
1504 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1505 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1506 strlcpy(alsa_handle.useCase, verb, sizeof(alsa_handle.useCase));
1507 } else {
1508 strlcpy(alsa_handle.useCase, modifier, sizeof(alsa_handle.useCase));
1509 }
1510 free(use_case);
1511
1512 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1513 bufferSize &= ~b;
1514 alsa_handle.module = mALSADevice;
1515 alsa_handle.bufferSize = bufferSize;
1516 alsa_handle.devices = device;
1517 alsa_handle.handle = 0;
1518 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1519 alsa_handle.channels = VOICE_CHANNEL_MODE;
1520 alsa_handle.sampleRate = VOICE_SAMPLING_RATE;
1521 alsa_handle.latency = VOICE_LATENCY;
1522 alsa_handle.rxHandle = 0;
1523 alsa_handle.ucMgr = mUcMgr;
1524 mDeviceList.push_back(alsa_handle);
1525 ALSAHandleList::iterator it = mDeviceList.end();
1526 it--;
Ajay Dudani9746c472012-06-18 16:01:16 -07001527#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001528 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1529 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1530 device |= AudioSystem::DEVICE_OUT_PROXY;
1531 alsa_handle.devices = device;
1532 }
1533#endif
1534 mALSADevice->route(&(*it), (uint32_t)device, mode);
1535 if (!strcmp(it->useCase, verb)) {
1536 snd_use_case_set(mUcMgr, "_verb", verb);
1537 } else {
1538 snd_use_case_set(mUcMgr, "_enamod", modifier);
1539 }
1540 mALSADevice->startVoiceCall(&(*it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001541#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001542 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1543 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1544 startUsbRecordingIfNotStarted();
1545 startUsbPlaybackIfNotStarted();
1546 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
1547 musbRecordingState |= USBRECBIT_VOICECALL;
1548 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001549#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001550}
1551
1552bool AudioHardwareALSA::routeVoiceCall(int device, int newMode)
1553{
1554int csCallState = mCallState&0xF;
1555 bool isRouted = false;
1556 switch (csCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001557 case CS_INACTIVE:
1558 if (mCSCallActive != CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001559 ALOGD("doRouting: Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001560 disableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1561 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1562 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001563 mCSCallActive = CS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001564 }
1565 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001566 case CS_ACTIVE:
1567 if (mCSCallActive == CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001568 ALOGD("doRouting: Enabling CS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001569 enableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1570 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1571 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001572 mCSCallActive = CS_ACTIVE;
1573 } else if (mCSCallActive == CS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001574 ALOGD("doRouting: Resume voice call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001575 ALSAHandleList::iterator vt_it;
1576 for(vt_it = mDeviceList.begin();
1577 vt_it != mDeviceList.end(); ++vt_it) {
1578 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1579 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1580 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1581 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
1582 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001583 mCSCallActive = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001584 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001585 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001586 break;
1587 }
1588 }
1589 }
1590 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001591 case CS_HOLD:
1592 if (mCSCallActive == CS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001593 ALOGD("doRouting: Voice call going to Hold");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001594 ALSAHandleList::iterator vt_it;
1595 for(vt_it = mDeviceList.begin();
1596 vt_it != mDeviceList.end(); ++vt_it) {
1597 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1598 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1599 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1600 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001601 mCSCallActive = CS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001602 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1603 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001604 ALOGE("Voice pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001605 break;
1606 }
1607 }
1608 }
1609 break;
1610 }
1611 return isRouted;
1612}
1613bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
1614{
1615int volteCallState = mCallState&0xF0;
1616bool isRouted = false;
1617switch (volteCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001618 case IMS_INACTIVE:
1619 if (mVolteCallActive != IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001620 ALOGD("doRouting: Disabling IMS call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001621 disableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1622 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1623 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001624 mVolteCallActive = IMS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001625 }
1626 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001627 case IMS_ACTIVE:
1628 if (mVolteCallActive == IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001629 ALOGD("doRouting: Enabling IMS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001630 enableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1631 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1632 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001633 mVolteCallActive = IMS_ACTIVE;
1634 } else if (mVolteCallActive == IMS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001635 ALOGD("doRouting: Resume IMS call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001636 ALSAHandleList::iterator vt_it;
1637 for(vt_it = mDeviceList.begin();
1638 vt_it != mDeviceList.end(); ++vt_it) {
1639 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1640 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1641 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1642 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
1643 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001644 mVolteCallActive = IMS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001645 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001646 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001647 break;
1648 }
1649 }
1650 }
1651 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001652 case IMS_HOLD:
1653 if (mVolteCallActive == IMS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001654 ALOGD("doRouting: IMS ACTIVE going to HOLD");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001655 ALSAHandleList::iterator vt_it;
1656 for(vt_it = mDeviceList.begin();
1657 vt_it != mDeviceList.end(); ++vt_it) {
1658 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1659 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1660 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1661 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001662 mVolteCallActive = IMS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001663 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1664 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001665 ALOGE("VoLTE Pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001666 break;
1667 }
1668 }
1669 }
1670 break;
1671 }
1672 return isRouted;
1673}
1674
1675} // namespace android_audio_legacy