blob: d108d225bd623415fe5a28929eb19f71c265f6b0 [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
46extern "C" {
Ajay Dudani9746c472012-06-18 16:01:16 -070047#ifdef QCOM_CSDCLIENT_ENABLED
48#include "csd_client.h"
49#endif
50#ifdef QCOM_ACDB_ENABLED
51#include "acdb-loader.h"
52#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -070053}
54
55extern "C"
56{
57 //
58 // Function for dlsym() to look up for creating a new AudioHardwareInterface.
59 //
60 android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {
61 return android_audio_legacy::AudioHardwareALSA::create();
62 }
63} // extern "C"
64
65namespace android_audio_legacy
66{
67
68// ----------------------------------------------------------------------------
69
70AudioHardwareInterface *AudioHardwareALSA::create() {
71 return new AudioHardwareALSA();
72}
73
74AudioHardwareALSA::AudioHardwareALSA() :
75 mALSADevice(0),mVoipStreamCount(0),mVoipMicMute(false),mVoipBitRate(0)
76 ,mCallState(0)
77{
78 FILE *fp;
79 char soundCardInfo[200];
80 hw_module_t *module;
81 char platform[128], baseband[128];
82 int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
83 (hw_module_t const**)&module);
84 int codec_rev = 2;
Iliyan Malchev4113f342012-06-11 14:39:47 -070085 ALOGD("hw_get_module(ALSA_HARDWARE_MODULE_ID) returned err %d", err);
Iliyan Malchev4765c432012-06-11 14:36:16 -070086 if (err == 0) {
87 hw_device_t* device;
88 err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);
89 if (err == 0) {
90 mALSADevice = (alsa_device_t *)device;
91 mALSADevice->init(mALSADevice, mDeviceList);
92 mCSCallActive = 0;
93 mVolteCallActive = 0;
94 mIsFmActive = 0;
95 mDevSettingsFlag = 0;
Ajay Dudani9746c472012-06-18 16:01:16 -070096#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -070097 mAudioUsbALSA = new AudioUsbALSA();
Ajay Dudani9746c472012-06-18 16:01:16 -070098 musbPlaybackState = 0;
99 musbRecordingState = 0;
100#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700101 mDevSettingsFlag |= TTY_OFF;
102 mBluetoothVGS = false;
103 mFusion3Platform = false;
Ajay Dudani9746c472012-06-18 16:01:16 -0700104
105#ifdef QCOM_ACDB_ENABLED
106 if ((acdb_loader_init_ACDB()) < 0) {
107 ALOGE("Failed to initialize ACDB");
108 }
109#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700110
111 if((fp = fopen("/proc/asound/cards","r")) == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700112 ALOGE("Cannot open /proc/asound/cards file to get sound card info");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700113 } else {
114 while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700115 ALOGV("SoundCardInfo %s", soundCardInfo);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700116 if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
117 codec_rev = 1;
118 break;
119 } else if (strstr(soundCardInfo, "msm-snd-card")) {
120 codec_rev = 2;
121 break;
122 } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
123 codec_rev = 3;
124 break;
125 }
126 }
127 fclose(fp);
128 }
129
130 if (codec_rev == 1) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700131 ALOGV("Detected tabla 1.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700132 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
133 } else if (codec_rev == 3) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700134 ALOGV("Detected sitar 1.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700135 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
136 } else {
137 property_get("ro.board.platform", platform, "");
138 property_get("ro.baseband", baseband, "");
139 if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700140 ALOGV("Detected Fusion tabla 2.x");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700141 mFusion3Platform = true;
142 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
143 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700144 ALOGV("Detected tabla 2.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700145 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
146 }
147 }
148
149 if (mUcMgr < 0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700150 ALOGE("Failed to open ucm instance: %d", errno);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700151 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700152 ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700153 }
154 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700155 ALOGE("ALSA Module could not be opened!!!");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700156 }
157 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700158 ALOGE("ALSA Module not found!!!");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700159 }
160}
161
162AudioHardwareALSA::~AudioHardwareALSA()
163{
164 if (mUcMgr != NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700165 ALOGD("closing ucm instance: %u", (unsigned)mUcMgr);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700166 snd_use_case_mgr_close(mUcMgr);
167 }
168 if (mALSADevice) {
169 mALSADevice->common.close(&mALSADevice->common);
170 }
171 for(ALSAHandleList::iterator it = mDeviceList.begin();
172 it != mDeviceList.end(); ++it) {
173 it->useCase[0] = 0;
174 mDeviceList.erase(it);
175 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700176#ifdef QCOM_ACDB_ENABLED
177 acdb_loader_deallocate_ACDB();
178#endif
179#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700180 delete mAudioUsbALSA;
Ajay Dudani9746c472012-06-18 16:01:16 -0700181#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700182}
183
184status_t AudioHardwareALSA::initCheck()
185{
186 if (!mALSADevice)
187 return NO_INIT;
188
189 return NO_ERROR;
190}
191
192status_t AudioHardwareALSA::setVoiceVolume(float v)
193{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700194 ALOGD("setVoiceVolume(%f)\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700195 if (v < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700196 ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700197 v = 0.0;
198 } else if (v > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700199 ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700200 v = 1.0;
201 }
202
203 int newMode = mode();
Iliyan Malchev4113f342012-06-11 14:39:47 -0700204 ALOGD("setVoiceVolume newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700205 int vol = lrint(v * 100.0);
206
207 // Voice volume levels from android are mapped to driver volume levels as follows.
208 // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
209 // So adjust the volume to get the correct volume index in driver
210 vol = 100 - vol;
211
212 if (mALSADevice) {
213 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
214 mALSADevice->setVoipVolume(vol);
215 } else if (newMode == AudioSystem::MODE_IN_CALL){
Ajay Dudani9746c472012-06-18 16:01:16 -0700216 if (mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700217 mALSADevice->setVoiceVolume(vol);
Ajay Dudani9746c472012-06-18 16:01:16 -0700218 if (mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700219 mALSADevice->setVoLTEVolume(vol);
220 }
221 }
222
223 return NO_ERROR;
224}
225
Ajay Dudani9746c472012-06-18 16:01:16 -0700226#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700227status_t AudioHardwareALSA::setFmVolume(float value)
228{
229 status_t status = NO_ERROR;
230
231 int vol;
232
233 if (value < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700234 ALOGW("setFmVolume(%f) under 0.0, assuming 0.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700235 value = 0.0;
236 } else if (value > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700237 ALOGW("setFmVolume(%f) over 1.0, assuming 1.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700238 value = 1.0;
239 }
240 vol = lrint((value * 0x2000) + 0.5);
241
Iliyan Malchev4113f342012-06-11 14:39:47 -0700242 ALOGD("setFmVolume(%f)\n", value);
243 ALOGD("Setting FM volume to %d (available range is 0 to 0x2000)\n", vol);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700244
245 mALSADevice->setFmVolume(vol);
246
247 return status;
248}
249#endif
250
251status_t AudioHardwareALSA::setMasterVolume(float volume)
252{
253 return NO_ERROR;
254}
255
256status_t AudioHardwareALSA::setMode(int mode)
257{
258 status_t status = NO_ERROR;
259
260 if (mode != mMode) {
261 status = AudioHardwareBase::setMode(mode);
262 }
263
264 if (mode == AudioSystem::MODE_IN_CALL) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700265 mCallState = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700266 }else if (mode == AudioSystem::MODE_NORMAL) {
267 mCallState = 0;
268 }
269
270 return status;
271}
272
273status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs)
274{
275 AudioParameter param = AudioParameter(keyValuePairs);
276 String8 key;
277 String8 value;
278 status_t status = NO_ERROR;
279 int device;
280 int btRate;
281 int state;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700282 ALOGD("setParameters() %s", keyValuePairs.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700283
284 key = String8(TTY_MODE_KEY);
285 if (param.get(key, value) == NO_ERROR) {
286 mDevSettingsFlag &= TTY_CLEAR;
287 if (value == "full") {
288 mDevSettingsFlag |= TTY_FULL;
289 } else if (value == "hco") {
290 mDevSettingsFlag |= TTY_HCO;
291 } else if (value == "vco") {
292 mDevSettingsFlag |= TTY_VCO;
293 } else {
294 mDevSettingsFlag |= TTY_OFF;
295 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700296 ALOGI("Changed TTY Mode=%s", value.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700297 mALSADevice->setFlags(mDevSettingsFlag);
298 if(mMode != AudioSystem::MODE_IN_CALL){
299 return NO_ERROR;
300 }
301 doRouting(0);
302 }
303
304 key = String8(FLUENCE_KEY);
305 if (param.get(key, value) == NO_ERROR) {
306 if (value == "quadmic") {
307 mDevSettingsFlag |= QMIC_FLAG;
308 mDevSettingsFlag &= (~DMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700309 ALOGV("Fluence quadMic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700310 } else if (value == "dualmic") {
311 mDevSettingsFlag |= DMIC_FLAG;
312 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700313 ALOGV("Fluence dualmic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700314 } else if (value == "none") {
315 mDevSettingsFlag &= (~DMIC_FLAG);
316 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700317 ALOGV("Fluence feature Disabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700318 }
319 mALSADevice->setFlags(mDevSettingsFlag);
320 doRouting(0);
321 }
322
Ajay Dudani9746c472012-06-18 16:01:16 -0700323#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700324 if (mFusion3Platform) {
325 key = String8(INCALLMUSIC_KEY);
326 if (param.get(key, value) == NO_ERROR) {
327 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700328 ALOGV("Enabling Incall Music setting in the setparameter\n");
Ajay Dudani9746c472012-06-18 16:01:16 -0700329 csd_client_start_playback();
Iliyan Malchev4765c432012-06-11 14:36:16 -0700330 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700331 ALOGV("Disabling Incall Music setting in the setparameter\n");
Ajay Dudani9746c472012-06-18 16:01:16 -0700332 csd_client_stop_playback();
Iliyan Malchev4765c432012-06-11 14:36:16 -0700333 }
334 }
335 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700336#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700337
338 key = String8(ANC_KEY);
339 if (param.get(key, value) == NO_ERROR) {
340 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700341 ALOGV("Enabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700342 mDevSettingsFlag |= ANC_FLAG;
343 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700344 ALOGV("Disabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700345 mDevSettingsFlag &= (~ANC_FLAG);
346 }
347 mALSADevice->setFlags(mDevSettingsFlag);
348 doRouting(0);
349 }
350
351 key = String8(AudioParameter::keyRouting);
352 if (param.getInt(key, device) == NO_ERROR) {
353 // Ignore routing if device is 0.
354 if(device) {
355 doRouting(device);
356 }
357 param.remove(key);
358 }
359
360 key = String8(BT_SAMPLERATE_KEY);
361 if (param.getInt(key, btRate) == NO_ERROR) {
362 mALSADevice->setBtscoRate(btRate);
363 param.remove(key);
364 }
365
366 key = String8(BTHEADSET_VGS);
367 if (param.get(key, value) == NO_ERROR) {
368 if (value == "on") {
369 mBluetoothVGS = true;
370 } else {
371 mBluetoothVGS = false;
372 }
373 }
374
375 key = String8(WIDEVOICE_KEY);
376 if (param.get(key, value) == NO_ERROR) {
377 bool flag = false;
378 if (value == "true") {
379 flag = true;
380 }
381 if(mALSADevice) {
382 mALSADevice->enableWideVoice(flag);
383 }
384 param.remove(key);
385 }
386
387 key = String8(VOIPRATE_KEY);
388 if (param.get(key, value) == NO_ERROR) {
389 mVoipBitRate = atoi(value);
390 param.remove(key);
391 }
392
393 key = String8(FENS_KEY);
394 if (param.get(key, value) == NO_ERROR) {
395 bool flag = false;
396 if (value == "true") {
397 flag = true;
398 }
399 if(mALSADevice) {
400 mALSADevice->enableFENS(flag);
401 }
402 param.remove(key);
403 }
404
Ajay Dudani9746c472012-06-18 16:01:16 -0700405#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700406 key = String8(AudioParameter::keyHandleFm);
407 if (param.getInt(key, device) == NO_ERROR) {
408 // Ignore if device is 0
409 if(device) {
410 handleFm(device);
411 }
412 param.remove(key);
413 }
414#endif
415
416 key = String8(ST_KEY);
417 if (param.get(key, value) == NO_ERROR) {
418 bool flag = false;
419 if (value == "true") {
420 flag = true;
421 }
422 if(mALSADevice) {
423 mALSADevice->enableSlowTalk(flag);
424 }
425 param.remove(key);
426 }
427 key = String8(MODE_CALL_KEY);
428 if (param.getInt(key,state) == NO_ERROR) {
429 if (mCallState != state) {
430 mCallState = state;
431 doRouting(0);
432 }
433 mCallState = state;
434 }
435 if (param.size()) {
436 status = BAD_VALUE;
437 }
438 return status;
439}
440
441String8 AudioHardwareALSA::getParameters(const String8& keys)
442{
443 AudioParameter param = AudioParameter(keys);
444 String8 value;
445
446 String8 key = String8(DUALMIC_KEY);
447 if (param.get(key, value) == NO_ERROR) {
448 value = String8("false");
449 param.add(key, value);
450 }
451
452 key = String8(FLUENCE_KEY);
453 if (param.get(key, value) == NO_ERROR) {
454 if ((mDevSettingsFlag & QMIC_FLAG) &&
455 (mDevSettingsFlag & ~DMIC_FLAG))
456 value = String8("quadmic");
457 else if ((mDevSettingsFlag & DMIC_FLAG) &&
458 (mDevSettingsFlag & ~QMIC_FLAG))
459 value = String8("dualmic");
460 else if ((mDevSettingsFlag & ~DMIC_FLAG) &&
461 (mDevSettingsFlag & ~QMIC_FLAG))
462 value = String8("none");
463 param.add(key, value);
464 }
465
Ajay Dudani9746c472012-06-18 16:01:16 -0700466#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700467 key = String8("Fm-radio");
468 if ( param.get(key,value) == NO_ERROR ) {
469 if ( mIsFmActive ) {
470 param.addInt(String8("isFMON"), true );
471 }
472 }
473#endif
474
475 key = String8(BTHEADSET_VGS);
476 if (param.get(key, value) == NO_ERROR) {
477 if(mBluetoothVGS)
478 param.addInt(String8("isVGS"), true);
479 }
480
Iliyan Malchev4113f342012-06-11 14:39:47 -0700481 ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700482 return param.toString();
483}
484
Ajay Dudani9746c472012-06-18 16:01:16 -0700485#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700486void AudioHardwareALSA::closeUSBPlayback()
487{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700488 ALOGV("closeUSBPlayback, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700489 musbPlaybackState = 0;
490 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_KILLTHREAD);
491}
492
493void AudioHardwareALSA::closeUSBRecording()
494{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700495 ALOGV("closeUSBRecording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700496 musbRecordingState = 0;
497 mAudioUsbALSA->exitRecordingThread(SIGNAL_EVENT_KILLTHREAD);
498}
499
500void AudioHardwareALSA::closeUsbPlaybackIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700501 ALOGV("closeUsbPlaybackIfNothingActive, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700502 if(!musbPlaybackState && mAudioUsbALSA != NULL) {
503 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_TIMEOUT);
504 }
505}
506
507void AudioHardwareALSA::closeUsbRecordingIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700508 ALOGV("closeUsbRecordingIfNothingActive, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700509 if(!musbRecordingState && mAudioUsbALSA != NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700510 ALOGD("Closing USB Recording Session as no stream is active");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700511 mAudioUsbALSA->setkillUsbRecordingThread(true);
512 }
513}
514
515void AudioHardwareALSA::startUsbPlaybackIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700516 ALOGV("Starting the USB playback %d kill %d", musbPlaybackState,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700517 mAudioUsbALSA->getkillUsbPlaybackThread());
518 if((!musbPlaybackState) || (mAudioUsbALSA->getkillUsbPlaybackThread() == true)) {
519 mAudioUsbALSA->startPlayback();
520 }
521}
522
523void AudioHardwareALSA::startUsbRecordingIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700524 ALOGV("Starting the recording musbRecordingState: %d killUsbRecordingThread %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700525 musbRecordingState, mAudioUsbALSA->getkillUsbRecordingThread());
526 if((!musbRecordingState) || (mAudioUsbALSA->getkillUsbRecordingThread() == true)) {
527 mAudioUsbALSA->startRecording();
528 }
529}
Ajay Dudani9746c472012-06-18 16:01:16 -0700530#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700531
532void AudioHardwareALSA::doRouting(int device)
533{
534 Mutex::Autolock autoLock(mLock);
535 int newMode = mode();
536 bool isRouted = false;
537
Ajay Dudani9746c472012-06-18 16:01:16 -0700538 if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
539#ifdef QCOM_FM_ENABLED
540 || (device == AudioSystem::DEVICE_IN_FM_RX)
541 || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT)
542 || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700543#endif
Ajay Dudani9746c472012-06-18 16:01:16 -0700544 || (device == AudioSystem::DEVICE_IN_COMMUNICATION)
545 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700546 ALOGV("Ignoring routing for FM/INCALL/VOIP recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700547 return;
548 }
549 if (device == 0)
550 device = mCurDevice;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700551 ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
Iliyan Malchev4765c432012-06-11 14:36:16 -0700552 "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
553 mIsFmActive);
554
555 isRouted = routeVoLTECall(device, newMode);
556 isRouted |= routeVoiceCall(device, newMode);
557
558 if(!isRouted) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700559#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700560 if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
561 !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
562 !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
563 (musbPlaybackState)){
564 //USB unplugged
565 device &= ~ AudioSystem::DEVICE_OUT_PROXY;
566 device &= ~ AudioSystem::DEVICE_IN_PROXY;
567 ALSAHandleList::iterator it = mDeviceList.end();
568 it--;
569 mALSADevice->route(&(*it), (uint32_t)device, newMode);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700570 ALOGE("USB UNPLUGGED, setting musbPlaybackState to 0");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700571 musbPlaybackState = 0;
572 musbRecordingState = 0;
573 closeUSBRecording();
574 closeUSBPlayback();
575 } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
576 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700577 ALOGE("Routing everything to prox now");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700578 ALSAHandleList::iterator it = mDeviceList.end();
579 it--;
580 mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
581 newMode);
582 for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
583 if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
584 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700585 ALOGD("doRouting: LPA device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700586 startUsbPlaybackIfNotStarted();
587 musbPlaybackState |= USBPLAYBACKBIT_LPA;
588 break;
589 } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
590 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700591 ALOGD("doRouting: VOICE device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700592 startUsbRecordingIfNotStarted();
593 startUsbPlaybackIfNotStarted();
594 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
595 musbRecordingState |= USBPLAYBACKBIT_VOICECALL;
596 break;
597 }else if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
598 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700599 ALOGD("doRouting: FM device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700600 startUsbPlaybackIfNotStarted();
601 musbPlaybackState |= USBPLAYBACKBIT_FM;
602 break;
603 }
604 }
605 } else
606#endif
607 if((((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
608 (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
609 (mCurDevice & AudioSystem::DEVICE_OUT_SPEAKER) &&
610 ((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
611 (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) ||
612 (((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
613 (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
614 (device & AudioSystem::DEVICE_OUT_SPEAKER) &&
615 ((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
616 (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)))) {
617 for(ALSAHandleList::iterator it = mDeviceList.begin();
618 it != mDeviceList.end(); ++it) {
619 if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI,
620 strlen(SND_USE_CASE_VERB_HIFI))) ||
621 (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
622 strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) {
623 mALSADevice->route(&(*it),(uint32_t)device, newMode);
624 break;
625 }
626 }
627 } else {
628 ALSAHandleList::iterator it = mDeviceList.end();
629 it--;
630 mALSADevice->route(&(*it), (uint32_t)device, newMode);
631 }
632 }
633 mCurDevice = device;
634}
635
636uint32_t AudioHardwareALSA::getVoipMode(int format)
637{
638 switch(format) {
639 case AudioSystem::PCM_16_BIT:
640 return MODE_PCM;
641 break;
642 case AudioSystem::AMR_NB:
643 return MODE_AMR;
644 break;
645 case AudioSystem::AMR_WB:
646 return MODE_AMR_WB;
647 break;
648
Ajay Dudani9746c472012-06-18 16:01:16 -0700649#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700650 case AudioSystem::EVRC:
651 return MODE_IS127;
652 break;
653
654 case AudioSystem::EVRCB:
655 return MODE_4GV_NB;
656 break;
657 case AudioSystem::EVRCWB:
658 return MODE_4GV_WB;
659 break;
Ajay Dudani9746c472012-06-18 16:01:16 -0700660#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700661
662 default:
663 return MODE_PCM;
664 }
665}
666
667AudioStreamOut *
668AudioHardwareALSA::openOutputStream(uint32_t devices,
669 int *format,
670 uint32_t *channels,
671 uint32_t *sampleRate,
672 status_t *status)
673{
674 Mutex::Autolock autoLock(mLock);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700675 ALOGD("openOutputStream: devices 0x%x channels %d sampleRate %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700676 devices, *channels, *sampleRate);
677
678 status_t err = BAD_VALUE;
679 AudioStreamOutALSA *out = 0;
680 ALSAHandleList::iterator it;
681
682 if (devices & (devices - 1)) {
683 if (status) *status = err;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700684 ALOGE("openOutputStream called with bad devices");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700685 return out;
686 }
687# if 0
688 if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
689 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
690 bool voipstream_active = false;
691 for(it = mDeviceList.begin();
692 it != mDeviceList.end(); ++it) {
693 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
694 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700695 ALOGD("openOutput: it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700696 voipstream_active = true;
697 break;
698 }
699 }
700 if(voipstream_active == false) {
701 mVoipStreamCount = 0;
702 mVoipMicMute = false;
703 alsa_handle_t alsa_handle;
704 unsigned long bufferSize;
705 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
706 bufferSize = VOIP_BUFFER_SIZE_8K;
707 }
708 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
709 bufferSize = VOIP_BUFFER_SIZE_16K;
710 }
711 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700712 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700713 if (status) *status = err;
714 return out;
715 }
716 alsa_handle.module = mALSADevice;
717 alsa_handle.bufferSize = bufferSize;
718 alsa_handle.devices = devices;
719 alsa_handle.handle = 0;
720 if(*format == AudioSystem::PCM_16_BIT)
721 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
722 else
723 alsa_handle.format = *format;
724 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
725 alsa_handle.sampleRate = *sampleRate;
726 alsa_handle.latency = VOIP_PLAYBACK_LATENCY;
727 alsa_handle.rxHandle = 0;
728 alsa_handle.ucMgr = mUcMgr;
729 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
730 char *use_case;
731 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
732 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
733 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
734 } else {
735 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
736 }
737 free(use_case);
738 mDeviceList.push_back(alsa_handle);
739 it = mDeviceList.end();
740 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700741 ALOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipStreamCount %d mode %d", it->useCase,mCurDevice,mVoipStreamCount, mode());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700742 if((mCurDevice & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
743 (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
744 (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700745 ALOGD("Routing to proxy for normal voip call in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700746 mCurDevice |= AudioSystem::DEVICE_OUT_PROXY;
747 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
748 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700749 ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700750 startUsbPlaybackIfNotStarted();
751 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700752 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700753 startUsbRecordingIfNotStarted();
754 musbRecordingState |= USBRECBIT_VOIPCALL;
755 } else{
756 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
757 }
758 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
759 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
760 } else {
761 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
762 }
763 err = mALSADevice->startVoipCall(&(*it));
764 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700765 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700766 return NULL;
767 }
768 }
769 out = new AudioStreamOutALSA(this, &(*it));
770 err = out->set(format, channels, sampleRate, devices);
771 if(err == NO_ERROR) {
772 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -0700773 ALOGD("openoutput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700774 }
775 if (status) *status = err;
776 return out;
777 } else
778#endif
779 {
780
781 alsa_handle_t alsa_handle;
782 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
783
784 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
785 bufferSize &= ~b;
786
787 alsa_handle.module = mALSADevice;
788 alsa_handle.bufferSize = bufferSize;
789 alsa_handle.devices = devices;
790 alsa_handle.handle = 0;
791 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
792 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
793 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
794 alsa_handle.latency = PLAYBACK_LATENCY;
795 alsa_handle.rxHandle = 0;
796 alsa_handle.ucMgr = mUcMgr;
797
798 char *use_case;
799 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
800 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
801 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
802 } else {
803 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
804 }
805 free(use_case);
806 mDeviceList.push_back(alsa_handle);
807 ALSAHandleList::iterator it = mDeviceList.end();
808 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700809 ALOGD("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700810#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700811 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
812 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700813 ALOGE("Routing to proxy for normal playback in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700814 devices |= AudioSystem::DEVICE_OUT_PROXY;
815 }
816#endif
817 mALSADevice->route(&(*it), devices, mode());
818 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
819 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
820 } else {
821 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
822 }
823 err = mALSADevice->open(&(*it));
824 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700825 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700826 } else {
827 out = new AudioStreamOutALSA(this, &(*it));
828 err = out->set(format, channels, sampleRate, devices);
829 }
830
831 if (status) *status = err;
832 return out;
833 }
834}
835
836void
837AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
838{
839 delete out;
840}
841
Ajay Dudani9746c472012-06-18 16:01:16 -0700842#ifdef QCOM_TUNNEL_LPA_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700843AudioStreamOut *
844AudioHardwareALSA::openOutputSession(uint32_t devices,
845 int *format,
846 status_t *status,
847 int sessionId,
848 uint32_t samplingRate,
849 uint32_t channels)
850{
851 Mutex::Autolock autoLock(mLock);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700852 ALOGD("openOutputSession = %d" ,sessionId);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700853 AudioStreamOutALSA *out = 0;
854 status_t err = BAD_VALUE;
855
856 alsa_handle_t alsa_handle;
857 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
858
859 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
860 bufferSize &= ~b;
861
862 alsa_handle.module = mALSADevice;
863 alsa_handle.bufferSize = bufferSize;
864 alsa_handle.devices = devices;
865 alsa_handle.handle = 0;
866 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
867 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
868 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
869 alsa_handle.latency = VOICE_LATENCY;
870 alsa_handle.rxHandle = 0;
871 alsa_handle.ucMgr = mUcMgr;
872
873 char *use_case;
874 if(sessionId == TUNNEL_SESSION_ID) {
875 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
876 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
877 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, sizeof(alsa_handle.useCase));
878 } else {
879 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, sizeof(alsa_handle.useCase));
880 }
881 } else {
882 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
883 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
884 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, sizeof(alsa_handle.useCase));
885 } else {
886 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LPA, sizeof(alsa_handle.useCase));
887 }
888 }
889 free(use_case);
890 mDeviceList.push_back(alsa_handle);
891 ALSAHandleList::iterator it = mDeviceList.end();
892 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700893 ALOGD("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700894#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700895 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
896 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700897 ALOGE("Routing to proxy for LPA in openOutputSession");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700898 devices |= AudioSystem::DEVICE_OUT_PROXY;
899 mALSADevice->route(&(*it), devices, mode());
900 devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700901 ALOGD("Starting USBPlayback for LPA");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700902 startUsbPlaybackIfNotStarted();
903 musbPlaybackState |= USBPLAYBACKBIT_LPA;
904 } else
905#endif
906 {
907 mALSADevice->route(&(*it), devices, mode());
908 }
909 if(sessionId == TUNNEL_SESSION_ID) {
910 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) {
911 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_TUNNEL);
912 } else {
913 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_TUNNEL);
914 }
915 }
916 else {
917 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) {
918 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOW_POWER);
919 } else {
920 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LPA);
921 }
922 }
923 err = mALSADevice->open(&(*it));
924 out = new AudioStreamOutALSA(this, &(*it));
925
926 if (status) *status = err;
927 return out;
928}
929
930void
931AudioHardwareALSA::closeOutputSession(AudioStreamOut* out)
932{
933 delete out;
934}
Ajay Dudani9746c472012-06-18 16:01:16 -0700935#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700936
937AudioStreamIn *
938AudioHardwareALSA::openInputStream(uint32_t devices,
939 int *format,
940 uint32_t *channels,
941 uint32_t *sampleRate,
942 status_t *status,
943 AudioSystem::audio_in_acoustics acoustics)
944{
945 Mutex::Autolock autoLock(mLock);
946 char *use_case;
947 int newMode = mode();
948 uint32_t route_devices;
949
950 status_t err = BAD_VALUE;
951 AudioStreamInALSA *in = 0;
952 ALSAHandleList::iterator it;
953
Iliyan Malchev4113f342012-06-11 14:39:47 -0700954 ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700955 if (devices & (devices - 1)) {
956 if (status) *status = err;
957 return in;
958 }
959
960 if((devices == AudioSystem::DEVICE_IN_COMMUNICATION) &&
961 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
962 bool voipstream_active = false;
963 for(it = mDeviceList.begin();
964 it != mDeviceList.end(); ++it) {
965 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
966 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700967 ALOGD("openInput: it->rxHandle %p it->handle %p",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700968 voipstream_active = true;
969 break;
970 }
971 }
972 if(voipstream_active == false) {
973 mVoipStreamCount = 0;
974 mVoipMicMute = false;
975 alsa_handle_t alsa_handle;
976 unsigned long bufferSize;
977 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
978 bufferSize = VOIP_BUFFER_SIZE_8K;
979 }
980 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
981 bufferSize = VOIP_BUFFER_SIZE_16K;
982 }
983 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700984 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700985 if (status) *status = err;
986 return in;
987 }
988 alsa_handle.module = mALSADevice;
989 alsa_handle.bufferSize = bufferSize;
990 alsa_handle.devices = devices;
991 alsa_handle.handle = 0;
992 if(*format == AudioSystem::PCM_16_BIT)
993 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
994 else
995 alsa_handle.format = *format;
996 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
997 alsa_handle.sampleRate = *sampleRate;
998 alsa_handle.latency = VOIP_RECORD_LATENCY;
999 alsa_handle.rxHandle = 0;
1000 alsa_handle.ucMgr = mUcMgr;
1001 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
1002 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1003 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1004 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
1005 } else {
1006 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
1007 }
1008 free(use_case);
1009 mDeviceList.push_back(alsa_handle);
1010 it = mDeviceList.end();
1011 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001012 ALOGE("mCurrDevice: %d", mCurDevice);
Ajay Dudani9746c472012-06-18 16:01:16 -07001013#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001014 if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1015 (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001016 ALOGE("Routing everything from proxy for voipcall");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001017 mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -07001018 ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001019 startUsbPlaybackIfNotStarted();
1020 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001021 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001022 startUsbRecordingIfNotStarted();
1023 musbRecordingState |= USBRECBIT_VOIPCALL;
1024 }else
1025#endif
1026 {
1027 mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
1028 }
1029 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
1030 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
1031 } else {
1032 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
1033 }
1034 if(sampleRate) {
1035 it->sampleRate = *sampleRate;
1036 }
1037 if(channels)
1038 it->channels = AudioSystem::popCount(*channels);
1039 err = mALSADevice->startVoipCall(&(*it));
1040 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001041 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001042 return NULL;
1043 }
1044 }
1045 in = new AudioStreamInALSA(this, &(*it), acoustics);
1046 err = in->set(format, channels, sampleRate, devices);
1047 if(err == NO_ERROR) {
1048 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -07001049 ALOGD("OpenInput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001050 }
Iliyan Malchev4113f342012-06-11 14:39:47 -07001051 ALOGE("openInput: After Get alsahandle");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001052 if (status) *status = err;
1053 return in;
1054 } else
1055 {
1056 for(ALSAHandleList::iterator itDev = mDeviceList.begin();
1057 itDev != mDeviceList.end(); ++itDev)
1058 {
1059 if((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_HIFI_REC, MAX_UC_LEN))
1060 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, MAX_UC_LEN))
1061 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_FM, MAX_UC_LEN))
Ajay Dudani9746c472012-06-18 16:01:16 -07001062#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001063 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_REC, MAX_UC_LEN))
1064#endif
1065 )
1066 {
Ajay Dudani9746c472012-06-18 16:01:16 -07001067#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001068 if(!(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001069 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001070 itDev->useCase, itDev->devices, itDev->module);
1071 return in;
1072 }
1073#endif
1074 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001075#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001076 else if ((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, MAX_UC_LEN))
1077 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, MAX_UC_LEN)))
1078 {
1079 if((devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001080 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001081 itDev->useCase, itDev->devices, itDev->module);
1082 return in;
1083 }
1084 }
1085#endif
1086 }
1087
1088 alsa_handle_t alsa_handle;
1089 unsigned long bufferSize = DEFAULT_IN_BUFFER_SIZE;
1090
1091 alsa_handle.module = mALSADevice;
1092 alsa_handle.bufferSize = bufferSize;
1093 alsa_handle.devices = devices;
1094 alsa_handle.handle = 0;
1095 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1096 alsa_handle.channels = VOICE_CHANNEL_MODE;
1097 alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
1098 alsa_handle.latency = RECORD_LATENCY;
1099 alsa_handle.rxHandle = 0;
1100 alsa_handle.ucMgr = mUcMgr;
1101 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1102 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1103 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1104 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001105 ALOGD("openInputStream: into incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001106 mIncallMode = *channels;
1107 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1108 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1109 if (mFusion3Platform) {
1110 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1111 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1112 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001113 } else {
1114 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
1115 sizeof(alsa_handle.useCase));
1116 }
1117 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1118 if (mFusion3Platform) {
1119 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1120 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1121 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001122 } else {
1123 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
1124 sizeof(alsa_handle.useCase));
1125 }
1126 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001127#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001128 } else if((devices == AudioSystem::DEVICE_IN_FM_RX)) {
1129 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(alsa_handle.useCase));
1130 } else if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1131 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
1132#endif
1133 } else {
1134 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(alsa_handle.useCase));
1135 }
1136 } else {
1137 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1138 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001139 ALOGD("openInputStream: incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001140 mIncallMode = *channels;
1141 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1142 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1143 if (mFusion3Platform) {
1144 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1145 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1146 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001147 } else {
1148 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
1149 sizeof(alsa_handle.useCase));
1150 }
1151 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1152 if (mFusion3Platform) {
1153 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1154 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1155 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001156 } else {
1157 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
1158 sizeof(alsa_handle.useCase));
1159 }
1160 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001161#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001162 } else if(devices == AudioSystem::DEVICE_IN_FM_RX) {
1163 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_REC, sizeof(alsa_handle.useCase));
1164 } else if (devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1165 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(alsa_handle.useCase));
1166#endif
1167 } else {
1168 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
1169 }
1170 }
1171 free(use_case);
1172 mDeviceList.push_back(alsa_handle);
1173 ALSAHandleList::iterator it = mDeviceList.end();
1174 it--;
1175 //update channel info before do routing
1176 if(channels) {
1177 it->channels = AudioSystem::popCount((*channels) &
Ajay Dudani9746c472012-06-18 16:01:16 -07001178 (AudioSystem::CHANNEL_IN_STEREO
1179 | AudioSystem::CHANNEL_IN_MONO
1180#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001181 | AudioSystem::CHANNEL_IN_5POINT1
1182#endif
1183 ));
Iliyan Malchev4113f342012-06-11 14:39:47 -07001184 ALOGV("updated channel info: channels=%d", it->channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001185 }
1186 if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
1187 /* Add current devices info to devices to do route */
Ajay Dudani9746c472012-06-18 16:01:16 -07001188#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001189 if(mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
1190 mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001191 ALOGD("Routing everything from proxy for VOIP call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001192 route_devices = devices | AudioSystem::DEVICE_IN_PROXY;
1193 } else
1194#endif
1195 {
1196 route_devices = devices | mCurDevice;
1197 }
1198 mALSADevice->route(&(*it), route_devices, mode());
1199 } else {
Ajay Dudani9746c472012-06-18 16:01:16 -07001200#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001201 if(devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET ||
1202 devices & AudioSystem::DEVICE_IN_PROXY) {
1203 devices |= AudioSystem::DEVICE_IN_PROXY;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001204 ALOGE("routing everything from proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001205 mALSADevice->route(&(*it), devices, mode());
1206 } else
1207#endif
1208 {
1209 mALSADevice->route(&(*it), devices, mode());
1210 }
1211 }
1212
1213 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
Ajay Dudani9746c472012-06-18 16:01:16 -07001214#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001215 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) ||
1216 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
1217#endif
1218 !strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) ||
1219 !strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
1220 !strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
1221 snd_use_case_set(mUcMgr, "_verb", it->useCase);
1222 } else {
1223 snd_use_case_set(mUcMgr, "_enamod", it->useCase);
1224 }
1225 if(sampleRate) {
1226 it->sampleRate = *sampleRate;
1227 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001228#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001229 if (6 == it->channels) {
1230 if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
1231 || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001232 ALOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001233 it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
1234 }
1235 }
1236#endif
1237 err = mALSADevice->open(&(*it));
1238 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001239 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001240 } else {
1241 in = new AudioStreamInALSA(this, &(*it), acoustics);
1242 err = in->set(format, channels, sampleRate, devices);
1243 }
1244 if (status) *status = err;
1245 return in;
1246 }
1247}
1248
1249void
1250AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
1251{
1252 delete in;
1253}
1254
1255status_t AudioHardwareALSA::setMicMute(bool state)
1256{
1257 int newMode = mode();
Iliyan Malchev4113f342012-06-11 14:39:47 -07001258 ALOGD("setMicMute newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001259 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1260 if (mVoipMicMute != state) {
1261 mVoipMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001262 ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001263 if(mALSADevice) {
1264 mALSADevice->setVoipMicMute(state);
1265 }
1266 }
1267 } else {
1268 if (mMicMute != state) {
1269 mMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001270 ALOGD("setMicMute: mMicMute %d", mMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001271 if(mALSADevice) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001272 if(mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001273 mALSADevice->setMicMute(state);
Ajay Dudani9746c472012-06-18 16:01:16 -07001274 if(mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001275 mALSADevice->setVoLTEMicMute(state);
1276 }
1277 }
1278 }
1279 return NO_ERROR;
1280}
1281
1282status_t AudioHardwareALSA::getMicMute(bool *state)
1283{
1284 int newMode = mode();
1285 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1286 *state = mVoipMicMute;
1287 } else {
1288 *state = mMicMute;
1289 }
1290 return NO_ERROR;
1291}
1292
1293status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
1294{
1295 return NO_ERROR;
1296}
1297
1298size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
1299{
1300 size_t bufferSize;
1301 if (format != AudioSystem::PCM_16_BIT
1302 && format != AudioSystem::AMR_NB
1303 && format != AudioSystem::AMR_WB
Ajay Dudani9746c472012-06-18 16:01:16 -07001304#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001305 && format != AudioSystem::EVRC
1306 && format != AudioSystem::EVRCB
Ajay Dudani9746c472012-06-18 16:01:16 -07001307 && format != AudioSystem::EVRCWB
1308#endif
1309 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001310 ALOGW("getInputBufferSize bad format: %d", format);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001311 return 0;
1312 }
1313 if(sampleRate == 16000) {
1314 bufferSize = DEFAULT_IN_BUFFER_SIZE * 2 * channelCount;
1315 } else if(sampleRate < 44100) {
1316 bufferSize = DEFAULT_IN_BUFFER_SIZE * channelCount;
1317 } else {
1318 bufferSize = DEFAULT_IN_BUFFER_SIZE * 12;
1319 }
1320 return bufferSize;
1321}
1322
Ajay Dudani9746c472012-06-18 16:01:16 -07001323#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001324void AudioHardwareALSA::handleFm(int device)
1325{
1326int newMode = mode();
1327 if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
1328 // Start FM Radio on current active device
1329 unsigned long bufferSize = FM_BUFFER_SIZE;
1330 alsa_handle_t alsa_handle;
1331 char *use_case;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001332 ALOGV("Start FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001333 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1334 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1335 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, sizeof(alsa_handle.useCase));
1336 } else {
1337 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_FM, sizeof(alsa_handle.useCase));
1338 }
1339 free(use_case);
1340
1341 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1342 bufferSize &= ~b;
1343 alsa_handle.module = mALSADevice;
1344 alsa_handle.bufferSize = bufferSize;
1345 alsa_handle.devices = device;
1346 alsa_handle.handle = 0;
1347 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1348 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
1349 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
1350 alsa_handle.latency = VOICE_LATENCY;
1351 alsa_handle.rxHandle = 0;
1352 alsa_handle.ucMgr = mUcMgr;
1353 mIsFmActive = 1;
1354 mDeviceList.push_back(alsa_handle);
1355 ALSAHandleList::iterator it = mDeviceList.end();
1356 it--;
1357 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1358 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1359 device |= AudioSystem::DEVICE_OUT_PROXY;
1360 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001361 ALOGE("Routing to proxy for FM case");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001362 }
1363 mALSADevice->route(&(*it), (uint32_t)device, newMode);
1364 if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) {
1365 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_DIGITAL_RADIO);
1366 } else {
1367 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
1368 }
1369 mALSADevice->startFm(&(*it));
1370 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1371 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001372 ALOGE("Starting FM, musbPlaybackState %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001373 startUsbPlaybackIfNotStarted();
1374 musbPlaybackState |= USBPLAYBACKBIT_FM;
1375 }
1376 } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
1377 //i Stop FM Radio
Iliyan Malchev4113f342012-06-11 14:39:47 -07001378 ALOGV("Stop FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001379 for(ALSAHandleList::iterator it = mDeviceList.begin();
1380 it != mDeviceList.end(); ++it) {
1381 if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
1382 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
1383 mALSADevice->close(&(*it));
1384 //mALSADevice->route(&(*it), (uint32_t)device, newMode);
1385 mDeviceList.erase(it);
1386 break;
1387 }
1388 }
1389 mIsFmActive = 0;
1390 musbPlaybackState &= ~USBPLAYBACKBIT_FM;
1391 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1392 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1393 closeUsbPlaybackIfNothingActive();
1394 }
1395 }
1396}
1397#endif
1398
1399void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, int device)
1400{
1401 for(ALSAHandleList::iterator it = mDeviceList.begin();
1402 it != mDeviceList.end(); ++it) {
1403 if((!strcmp(it->useCase, verb)) ||
1404 (!strcmp(it->useCase, modifier))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001405 ALOGV("Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001406 mALSADevice->close(&(*it));
1407 mALSADevice->route(&(*it), (uint32_t)device, mode);
1408 mDeviceList.erase(it);
1409 break;
1410 }
1411 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001412#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001413 if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001414 ALOGE("Voice call ended on USB");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001415 musbPlaybackState &= ~USBPLAYBACKBIT_VOICECALL;
1416 musbRecordingState &= ~USBRECBIT_VOICECALL;
1417 closeUsbRecordingIfNothingActive();
1418 closeUsbPlaybackIfNothingActive();
1419 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001420#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001421}
1422void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, int device)
1423{
1424// Start voice call
1425unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
1426alsa_handle_t alsa_handle;
1427char *use_case;
1428 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1429 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1430 strlcpy(alsa_handle.useCase, verb, sizeof(alsa_handle.useCase));
1431 } else {
1432 strlcpy(alsa_handle.useCase, modifier, sizeof(alsa_handle.useCase));
1433 }
1434 free(use_case);
1435
1436 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1437 bufferSize &= ~b;
1438 alsa_handle.module = mALSADevice;
1439 alsa_handle.bufferSize = bufferSize;
1440 alsa_handle.devices = device;
1441 alsa_handle.handle = 0;
1442 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1443 alsa_handle.channels = VOICE_CHANNEL_MODE;
1444 alsa_handle.sampleRate = VOICE_SAMPLING_RATE;
1445 alsa_handle.latency = VOICE_LATENCY;
1446 alsa_handle.rxHandle = 0;
1447 alsa_handle.ucMgr = mUcMgr;
1448 mDeviceList.push_back(alsa_handle);
1449 ALSAHandleList::iterator it = mDeviceList.end();
1450 it--;
Ajay Dudani9746c472012-06-18 16:01:16 -07001451#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001452 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1453 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1454 device |= AudioSystem::DEVICE_OUT_PROXY;
1455 alsa_handle.devices = device;
1456 }
1457#endif
1458 mALSADevice->route(&(*it), (uint32_t)device, mode);
1459 if (!strcmp(it->useCase, verb)) {
1460 snd_use_case_set(mUcMgr, "_verb", verb);
1461 } else {
1462 snd_use_case_set(mUcMgr, "_enamod", modifier);
1463 }
1464 mALSADevice->startVoiceCall(&(*it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001465#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001466 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1467 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1468 startUsbRecordingIfNotStarted();
1469 startUsbPlaybackIfNotStarted();
1470 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
1471 musbRecordingState |= USBRECBIT_VOICECALL;
1472 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001473#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001474}
1475
1476bool AudioHardwareALSA::routeVoiceCall(int device, int newMode)
1477{
1478int csCallState = mCallState&0xF;
1479 bool isRouted = false;
1480 switch (csCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001481 case CS_INACTIVE:
1482 if (mCSCallActive != CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001483 ALOGD("doRouting: Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001484 disableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1485 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1486 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001487 mCSCallActive = CS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001488 }
1489 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001490 case CS_ACTIVE:
1491 if (mCSCallActive == CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001492 ALOGD("doRouting: Enabling CS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001493 enableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1494 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1495 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001496 mCSCallActive = CS_ACTIVE;
1497 } else if (mCSCallActive == CS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001498 ALOGD("doRouting: Resume voice call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001499 ALSAHandleList::iterator vt_it;
1500 for(vt_it = mDeviceList.begin();
1501 vt_it != mDeviceList.end(); ++vt_it) {
1502 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1503 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1504 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1505 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
1506 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001507 mCSCallActive = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001508 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001509 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001510 break;
1511 }
1512 }
1513 }
1514 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001515 case CS_HOLD:
1516 if (mCSCallActive == CS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001517 ALOGD("doRouting: Voice call going to Hold");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001518 ALSAHandleList::iterator vt_it;
1519 for(vt_it = mDeviceList.begin();
1520 vt_it != mDeviceList.end(); ++vt_it) {
1521 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1522 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1523 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1524 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001525 mCSCallActive = CS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001526 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1527 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001528 ALOGE("Voice pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001529 break;
1530 }
1531 }
1532 }
1533 break;
1534 }
1535 return isRouted;
1536}
1537bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
1538{
1539int volteCallState = mCallState&0xF0;
1540bool isRouted = false;
1541switch (volteCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001542 case IMS_INACTIVE:
1543 if (mVolteCallActive != IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001544 ALOGD("doRouting: Disabling IMS call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001545 disableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1546 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1547 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001548 mVolteCallActive = IMS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001549 }
1550 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001551 case IMS_ACTIVE:
1552 if (mVolteCallActive == IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001553 ALOGD("doRouting: Enabling IMS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001554 enableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1555 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1556 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001557 mVolteCallActive = IMS_ACTIVE;
1558 } else if (mVolteCallActive == IMS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001559 ALOGD("doRouting: Resume IMS call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001560 ALSAHandleList::iterator vt_it;
1561 for(vt_it = mDeviceList.begin();
1562 vt_it != mDeviceList.end(); ++vt_it) {
1563 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1564 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1565 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1566 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
1567 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001568 mVolteCallActive = IMS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001569 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001570 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001571 break;
1572 }
1573 }
1574 }
1575 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001576 case IMS_HOLD:
1577 if (mVolteCallActive == IMS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001578 ALOGD("doRouting: IMS ACTIVE going to HOLD");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001579 ALSAHandleList::iterator vt_it;
1580 for(vt_it = mDeviceList.begin();
1581 vt_it != mDeviceList.end(); ++vt_it) {
1582 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1583 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1584 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1585 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001586 mVolteCallActive = IMS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001587 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1588 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001589 ALOGE("VoLTE Pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001590 break;
1591 }
1592 }
1593 }
1594 break;
1595 }
1596 return isRouted;
1597}
1598
1599} // namespace android_audio_legacy