blob: a0057de0380e46b68c4921fdbd1933d3506ccecb [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
ty.lee924f7982012-08-01 23:15:30 +0900101#ifdef USES_FLUENCE_INCALL
102 mDevSettingsFlag |= TTY_OFF | DMIC_FLAG;
103#else
Iliyan Malchev4765c432012-06-11 14:36:16 -0700104 mDevSettingsFlag |= TTY_OFF;
ty.lee924f7982012-08-01 23:15:30 +0900105#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700106 mBluetoothVGS = false;
107 mFusion3Platform = false;
Ajay Dudani9746c472012-06-18 16:01:16 -0700108
109#ifdef QCOM_ACDB_ENABLED
110 if ((acdb_loader_init_ACDB()) < 0) {
111 ALOGE("Failed to initialize ACDB");
112 }
113#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700114
115 if((fp = fopen("/proc/asound/cards","r")) == NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700116 ALOGE("Cannot open /proc/asound/cards file to get sound card info");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700117 } else {
118 while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700119 ALOGV("SoundCardInfo %s", soundCardInfo);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700120 if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
121 codec_rev = 1;
122 break;
123 } else if (strstr(soundCardInfo, "msm-snd-card")) {
124 codec_rev = 2;
125 break;
126 } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
127 codec_rev = 3;
128 break;
129 }
130 }
131 fclose(fp);
132 }
133
134 if (codec_rev == 1) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700135 ALOGV("Detected tabla 1.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700136 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
137 } else if (codec_rev == 3) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700138 ALOGV("Detected sitar 1.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700139 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
140 } else {
141 property_get("ro.board.platform", platform, "");
142 property_get("ro.baseband", baseband, "");
143 if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700144 ALOGV("Detected Fusion tabla 2.x");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700145 mFusion3Platform = true;
146 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
147 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700148 ALOGV("Detected tabla 2.x sound card");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700149 snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
150 }
151 }
152
153 if (mUcMgr < 0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700154 ALOGE("Failed to open ucm instance: %d", errno);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700155 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700156 ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700157 }
158 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700159 ALOGE("ALSA Module could not be opened!!!");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700160 }
161 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700162 ALOGE("ALSA Module not found!!!");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700163 }
164}
165
166AudioHardwareALSA::~AudioHardwareALSA()
167{
168 if (mUcMgr != NULL) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700169#if LOCAL_LOGD
Iliyan Malchev4113f342012-06-11 14:39:47 -0700170 ALOGD("closing ucm instance: %u", (unsigned)mUcMgr);
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700171#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700172 snd_use_case_mgr_close(mUcMgr);
173 }
174 if (mALSADevice) {
175 mALSADevice->common.close(&mALSADevice->common);
176 }
177 for(ALSAHandleList::iterator it = mDeviceList.begin();
178 it != mDeviceList.end(); ++it) {
179 it->useCase[0] = 0;
180 mDeviceList.erase(it);
181 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700182#ifdef QCOM_ACDB_ENABLED
183 acdb_loader_deallocate_ACDB();
184#endif
185#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700186 delete mAudioUsbALSA;
Ajay Dudani9746c472012-06-18 16:01:16 -0700187#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700188}
189
190status_t AudioHardwareALSA::initCheck()
191{
192 if (!mALSADevice)
193 return NO_INIT;
194
195 return NO_ERROR;
196}
197
198status_t AudioHardwareALSA::setVoiceVolume(float v)
199{
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700200 ALOGV("setVoiceVolume(%f)\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700201 if (v < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700202 ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700203 v = 0.0;
204 } else if (v > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700205 ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700206 v = 1.0;
207 }
208
209 int newMode = mode();
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700210 ALOGV("setVoiceVolume newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700211 int vol = lrint(v * 100.0);
212
213 // Voice volume levels from android are mapped to driver volume levels as follows.
214 // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
215 // So adjust the volume to get the correct volume index in driver
216 vol = 100 - vol;
217
218 if (mALSADevice) {
219 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
220 mALSADevice->setVoipVolume(vol);
221 } else if (newMode == AudioSystem::MODE_IN_CALL){
Ajay Dudani9746c472012-06-18 16:01:16 -0700222 if (mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700223 mALSADevice->setVoiceVolume(vol);
Ajay Dudani9746c472012-06-18 16:01:16 -0700224 if (mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700225 mALSADevice->setVoLTEVolume(vol);
226 }
227 }
228
229 return NO_ERROR;
230}
231
Ajay Dudani9746c472012-06-18 16:01:16 -0700232#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700233status_t AudioHardwareALSA::setFmVolume(float value)
234{
235 status_t status = NO_ERROR;
236
237 int vol;
238
239 if (value < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700240 ALOGW("setFmVolume(%f) under 0.0, assuming 0.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700241 value = 0.0;
242 } else if (value > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700243 ALOGW("setFmVolume(%f) over 1.0, assuming 1.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700244 value = 1.0;
245 }
246 vol = lrint((value * 0x2000) + 0.5);
247
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700248#if LOCAL_LOGD
Iliyan Malchev4113f342012-06-11 14:39:47 -0700249 ALOGD("setFmVolume(%f)\n", value);
250 ALOGD("Setting FM volume to %d (available range is 0 to 0x2000)\n", vol);
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700251#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700252
253 mALSADevice->setFmVolume(vol);
254
255 return status;
256}
257#endif
258
259status_t AudioHardwareALSA::setMasterVolume(float volume)
260{
261 return NO_ERROR;
262}
263
264status_t AudioHardwareALSA::setMode(int mode)
265{
266 status_t status = NO_ERROR;
267
268 if (mode != mMode) {
269 status = AudioHardwareBase::setMode(mode);
270 }
271
272 if (mode == AudioSystem::MODE_IN_CALL) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700273 mCallState = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700274 }else if (mode == AudioSystem::MODE_NORMAL) {
275 mCallState = 0;
276 }
277
278 return status;
279}
280
281status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs)
282{
283 AudioParameter param = AudioParameter(keyValuePairs);
284 String8 key;
285 String8 value;
286 status_t status = NO_ERROR;
287 int device;
288 int btRate;
289 int state;
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700290#if LOCAL_LOGD
Iliyan Malchev4113f342012-06-11 14:39:47 -0700291 ALOGD("setParameters() %s", keyValuePairs.string());
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700292#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700293
294 key = String8(TTY_MODE_KEY);
295 if (param.get(key, value) == NO_ERROR) {
296 mDevSettingsFlag &= TTY_CLEAR;
ty.leea97e6f62012-08-15 10:11:50 +0900297 if (value == "tty_full") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700298 mDevSettingsFlag |= TTY_FULL;
ty.leea97e6f62012-08-15 10:11:50 +0900299 } else if (value == "tty_hco") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700300 mDevSettingsFlag |= TTY_HCO;
ty.leea97e6f62012-08-15 10:11:50 +0900301 } else if (value == "tty_vco") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700302 mDevSettingsFlag |= TTY_VCO;
303 } else {
304 mDevSettingsFlag |= TTY_OFF;
305 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700306 ALOGI("Changed TTY Mode=%s", value.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700307 mALSADevice->setFlags(mDevSettingsFlag);
308 if(mMode != AudioSystem::MODE_IN_CALL){
309 return NO_ERROR;
310 }
311 doRouting(0);
312 }
313
314 key = String8(FLUENCE_KEY);
315 if (param.get(key, value) == NO_ERROR) {
316 if (value == "quadmic") {
317 mDevSettingsFlag |= QMIC_FLAG;
318 mDevSettingsFlag &= (~DMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700319 ALOGV("Fluence quadMic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700320 } else if (value == "dualmic") {
321 mDevSettingsFlag |= DMIC_FLAG;
322 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700323 ALOGV("Fluence dualmic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700324 } else if (value == "none") {
325 mDevSettingsFlag &= (~DMIC_FLAG);
326 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700327 ALOGV("Fluence feature Disabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700328 }
329 mALSADevice->setFlags(mDevSettingsFlag);
330 doRouting(0);
331 }
332
Ajay Dudani9746c472012-06-18 16:01:16 -0700333#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700334 if (mFusion3Platform) {
335 key = String8(INCALLMUSIC_KEY);
336 if (param.get(key, value) == NO_ERROR) {
337 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700338 ALOGV("Enabling Incall Music setting in the setparameter\n");
Ajay Dudani9746c472012-06-18 16:01:16 -0700339 csd_client_start_playback();
Iliyan Malchev4765c432012-06-11 14:36:16 -0700340 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700341 ALOGV("Disabling Incall Music setting in the setparameter\n");
Ajay Dudani9746c472012-06-18 16:01:16 -0700342 csd_client_stop_playback();
Iliyan Malchev4765c432012-06-11 14:36:16 -0700343 }
344 }
345 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700346#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700347
348 key = String8(ANC_KEY);
349 if (param.get(key, value) == NO_ERROR) {
350 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700351 ALOGV("Enabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700352 mDevSettingsFlag |= ANC_FLAG;
353 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700354 ALOGV("Disabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700355 mDevSettingsFlag &= (~ANC_FLAG);
356 }
357 mALSADevice->setFlags(mDevSettingsFlag);
358 doRouting(0);
359 }
360
361 key = String8(AudioParameter::keyRouting);
362 if (param.getInt(key, device) == NO_ERROR) {
363 // Ignore routing if device is 0.
364 if(device) {
365 doRouting(device);
366 }
367 param.remove(key);
368 }
369
370 key = String8(BT_SAMPLERATE_KEY);
371 if (param.getInt(key, btRate) == NO_ERROR) {
372 mALSADevice->setBtscoRate(btRate);
373 param.remove(key);
374 }
375
376 key = String8(BTHEADSET_VGS);
377 if (param.get(key, value) == NO_ERROR) {
378 if (value == "on") {
379 mBluetoothVGS = true;
380 } else {
381 mBluetoothVGS = false;
382 }
383 }
384
385 key = String8(WIDEVOICE_KEY);
386 if (param.get(key, value) == NO_ERROR) {
387 bool flag = false;
388 if (value == "true") {
389 flag = true;
390 }
391 if(mALSADevice) {
392 mALSADevice->enableWideVoice(flag);
393 }
394 param.remove(key);
395 }
396
397 key = String8(VOIPRATE_KEY);
398 if (param.get(key, value) == NO_ERROR) {
399 mVoipBitRate = atoi(value);
400 param.remove(key);
401 }
402
403 key = String8(FENS_KEY);
404 if (param.get(key, value) == NO_ERROR) {
405 bool flag = false;
406 if (value == "true") {
407 flag = true;
408 }
409 if(mALSADevice) {
410 mALSADevice->enableFENS(flag);
411 }
412 param.remove(key);
413 }
414
Ajay Dudani9746c472012-06-18 16:01:16 -0700415#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700416 key = String8(AudioParameter::keyHandleFm);
417 if (param.getInt(key, device) == NO_ERROR) {
418 // Ignore if device is 0
419 if(device) {
420 handleFm(device);
421 }
422 param.remove(key);
423 }
424#endif
425
426 key = String8(ST_KEY);
427 if (param.get(key, value) == NO_ERROR) {
428 bool flag = false;
429 if (value == "true") {
430 flag = true;
431 }
432 if(mALSADevice) {
433 mALSADevice->enableSlowTalk(flag);
434 }
435 param.remove(key);
436 }
437 key = String8(MODE_CALL_KEY);
438 if (param.getInt(key,state) == NO_ERROR) {
439 if (mCallState != state) {
440 mCallState = state;
441 doRouting(0);
442 }
443 mCallState = state;
444 }
445 if (param.size()) {
446 status = BAD_VALUE;
447 }
448 return status;
449}
450
451String8 AudioHardwareALSA::getParameters(const String8& keys)
452{
453 AudioParameter param = AudioParameter(keys);
454 String8 value;
455
456 String8 key = String8(DUALMIC_KEY);
457 if (param.get(key, value) == NO_ERROR) {
458 value = String8("false");
459 param.add(key, value);
460 }
461
462 key = String8(FLUENCE_KEY);
463 if (param.get(key, value) == NO_ERROR) {
464 if ((mDevSettingsFlag & QMIC_FLAG) &&
465 (mDevSettingsFlag & ~DMIC_FLAG))
466 value = String8("quadmic");
467 else if ((mDevSettingsFlag & DMIC_FLAG) &&
468 (mDevSettingsFlag & ~QMIC_FLAG))
469 value = String8("dualmic");
470 else if ((mDevSettingsFlag & ~DMIC_FLAG) &&
471 (mDevSettingsFlag & ~QMIC_FLAG))
472 value = String8("none");
473 param.add(key, value);
474 }
475
Ajay Dudani9746c472012-06-18 16:01:16 -0700476#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700477 key = String8("Fm-radio");
478 if ( param.get(key,value) == NO_ERROR ) {
479 if ( mIsFmActive ) {
480 param.addInt(String8("isFMON"), true );
481 }
482 }
483#endif
484
485 key = String8(BTHEADSET_VGS);
486 if (param.get(key, value) == NO_ERROR) {
487 if(mBluetoothVGS)
488 param.addInt(String8("isVGS"), true);
489 }
490
Iliyan Malchev4113f342012-06-11 14:39:47 -0700491 ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700492 return param.toString();
493}
494
Ajay Dudani9746c472012-06-18 16:01:16 -0700495#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700496void AudioHardwareALSA::closeUSBPlayback()
497{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700498 ALOGV("closeUSBPlayback, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700499 musbPlaybackState = 0;
500 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_KILLTHREAD);
501}
502
503void AudioHardwareALSA::closeUSBRecording()
504{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700505 ALOGV("closeUSBRecording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700506 musbRecordingState = 0;
507 mAudioUsbALSA->exitRecordingThread(SIGNAL_EVENT_KILLTHREAD);
508}
509
510void AudioHardwareALSA::closeUsbPlaybackIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700511 ALOGV("closeUsbPlaybackIfNothingActive, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700512 if(!musbPlaybackState && mAudioUsbALSA != NULL) {
513 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_TIMEOUT);
514 }
515}
516
517void AudioHardwareALSA::closeUsbRecordingIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700518 ALOGV("closeUsbRecordingIfNothingActive, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700519 if(!musbRecordingState && mAudioUsbALSA != NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700520 ALOGD("Closing USB Recording Session as no stream is active");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700521 mAudioUsbALSA->setkillUsbRecordingThread(true);
522 }
523}
524
525void AudioHardwareALSA::startUsbPlaybackIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700526 ALOGV("Starting the USB playback %d kill %d", musbPlaybackState,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700527 mAudioUsbALSA->getkillUsbPlaybackThread());
528 if((!musbPlaybackState) || (mAudioUsbALSA->getkillUsbPlaybackThread() == true)) {
529 mAudioUsbALSA->startPlayback();
530 }
531}
532
533void AudioHardwareALSA::startUsbRecordingIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700534 ALOGV("Starting the recording musbRecordingState: %d killUsbRecordingThread %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700535 musbRecordingState, mAudioUsbALSA->getkillUsbRecordingThread());
536 if((!musbRecordingState) || (mAudioUsbALSA->getkillUsbRecordingThread() == true)) {
537 mAudioUsbALSA->startRecording();
538 }
539}
Ajay Dudani9746c472012-06-18 16:01:16 -0700540#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700541
542void AudioHardwareALSA::doRouting(int device)
543{
544 Mutex::Autolock autoLock(mLock);
545 int newMode = mode();
546 bool isRouted = false;
547
Ajay Dudani9746c472012-06-18 16:01:16 -0700548 if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
549#ifdef QCOM_FM_ENABLED
550 || (device == AudioSystem::DEVICE_IN_FM_RX)
551 || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT)
552 || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700553#endif
Ajay Dudani9746c472012-06-18 16:01:16 -0700554 || (device == AudioSystem::DEVICE_IN_COMMUNICATION)
555 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700556 ALOGV("Ignoring routing for FM/INCALL/VOIP recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700557 return;
558 }
559 if (device == 0)
560 device = mCurDevice;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700561 ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
Iliyan Malchev4765c432012-06-11 14:36:16 -0700562 "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
563 mIsFmActive);
564
565 isRouted = routeVoLTECall(device, newMode);
566 isRouted |= routeVoiceCall(device, newMode);
567
568 if(!isRouted) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700569#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700570 if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
571 !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
572 !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
573 (musbPlaybackState)){
574 //USB unplugged
575 device &= ~ AudioSystem::DEVICE_OUT_PROXY;
576 device &= ~ AudioSystem::DEVICE_IN_PROXY;
577 ALSAHandleList::iterator it = mDeviceList.end();
578 it--;
579 mALSADevice->route(&(*it), (uint32_t)device, newMode);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700580 ALOGE("USB UNPLUGGED, setting musbPlaybackState to 0");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700581 musbPlaybackState = 0;
582 musbRecordingState = 0;
583 closeUSBRecording();
584 closeUSBPlayback();
585 } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
586 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700587 ALOGE("Routing everything to prox now");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700588 ALSAHandleList::iterator it = mDeviceList.end();
589 it--;
590 mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
591 newMode);
592 for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
593 if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
594 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700595 ALOGV("doRouting: LPA device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700596 startUsbPlaybackIfNotStarted();
597 musbPlaybackState |= USBPLAYBACKBIT_LPA;
598 break;
599 } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
600 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700601 ALOGV("doRouting: VOICE device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700602 startUsbRecordingIfNotStarted();
603 startUsbPlaybackIfNotStarted();
604 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
605 musbRecordingState |= USBPLAYBACKBIT_VOICECALL;
606 break;
607 }else if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
608 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700609 ALOGV("doRouting: FM device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700610 startUsbPlaybackIfNotStarted();
611 musbPlaybackState |= USBPLAYBACKBIT_FM;
612 break;
613 }
614 }
615 } else
616#endif
617 if((((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
618 (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
619 (mCurDevice & AudioSystem::DEVICE_OUT_SPEAKER) &&
620 ((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
621 (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) ||
622 (((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
623 (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
624 (device & AudioSystem::DEVICE_OUT_SPEAKER) &&
625 ((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
626 (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)))) {
627 for(ALSAHandleList::iterator it = mDeviceList.begin();
628 it != mDeviceList.end(); ++it) {
629 if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI,
630 strlen(SND_USE_CASE_VERB_HIFI))) ||
631 (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
632 strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) {
633 mALSADevice->route(&(*it),(uint32_t)device, newMode);
634 break;
635 }
636 }
637 } else {
638 ALSAHandleList::iterator it = mDeviceList.end();
639 it--;
640 mALSADevice->route(&(*it), (uint32_t)device, newMode);
641 }
642 }
643 mCurDevice = device;
644}
645
646uint32_t AudioHardwareALSA::getVoipMode(int format)
647{
648 switch(format) {
649 case AudioSystem::PCM_16_BIT:
650 return MODE_PCM;
651 break;
652 case AudioSystem::AMR_NB:
653 return MODE_AMR;
654 break;
655 case AudioSystem::AMR_WB:
656 return MODE_AMR_WB;
657 break;
658
Ajay Dudani9746c472012-06-18 16:01:16 -0700659#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700660 case AudioSystem::EVRC:
661 return MODE_IS127;
662 break;
663
664 case AudioSystem::EVRCB:
665 return MODE_4GV_NB;
666 break;
667 case AudioSystem::EVRCWB:
668 return MODE_4GV_WB;
669 break;
Ajay Dudani9746c472012-06-18 16:01:16 -0700670#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700671
672 default:
673 return MODE_PCM;
674 }
675}
676
677AudioStreamOut *
678AudioHardwareALSA::openOutputStream(uint32_t devices,
679 int *format,
680 uint32_t *channels,
681 uint32_t *sampleRate,
682 status_t *status)
683{
684 Mutex::Autolock autoLock(mLock);
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700685 ALOGV("openOutputStream: devices 0x%x channels %d sampleRate %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700686 devices, *channels, *sampleRate);
687
688 status_t err = BAD_VALUE;
689 AudioStreamOutALSA *out = 0;
690 ALSAHandleList::iterator it;
691
692 if (devices & (devices - 1)) {
693 if (status) *status = err;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700694 ALOGE("openOutputStream called with bad devices");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700695 return out;
696 }
697# if 0
698 if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
699 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
700 bool voipstream_active = false;
701 for(it = mDeviceList.begin();
702 it != mDeviceList.end(); ++it) {
703 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
704 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700705 ALOGD("openOutput: it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700706 voipstream_active = true;
707 break;
708 }
709 }
710 if(voipstream_active == false) {
711 mVoipStreamCount = 0;
712 mVoipMicMute = false;
713 alsa_handle_t alsa_handle;
714 unsigned long bufferSize;
715 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
716 bufferSize = VOIP_BUFFER_SIZE_8K;
717 }
718 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
719 bufferSize = VOIP_BUFFER_SIZE_16K;
720 }
721 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700722 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700723 if (status) *status = err;
724 return out;
725 }
726 alsa_handle.module = mALSADevice;
727 alsa_handle.bufferSize = bufferSize;
728 alsa_handle.devices = devices;
729 alsa_handle.handle = 0;
730 if(*format == AudioSystem::PCM_16_BIT)
731 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
732 else
733 alsa_handle.format = *format;
734 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
735 alsa_handle.sampleRate = *sampleRate;
736 alsa_handle.latency = VOIP_PLAYBACK_LATENCY;
737 alsa_handle.rxHandle = 0;
738 alsa_handle.ucMgr = mUcMgr;
739 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
740 char *use_case;
741 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
742 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
743 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
744 } else {
745 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
746 }
747 free(use_case);
748 mDeviceList.push_back(alsa_handle);
749 it = mDeviceList.end();
750 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700751 ALOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipStreamCount %d mode %d", it->useCase,mCurDevice,mVoipStreamCount, mode());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700752 if((mCurDevice & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
753 (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
754 (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700755 ALOGD("Routing to proxy for normal voip call in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700756 mCurDevice |= AudioSystem::DEVICE_OUT_PROXY;
757 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
758 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700759 ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700760 startUsbPlaybackIfNotStarted();
761 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700762 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700763 startUsbRecordingIfNotStarted();
764 musbRecordingState |= USBRECBIT_VOIPCALL;
765 } else{
766 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
767 }
768 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
769 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
770 } else {
771 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
772 }
773 err = mALSADevice->startVoipCall(&(*it));
774 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700775 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700776 return NULL;
777 }
778 }
779 out = new AudioStreamOutALSA(this, &(*it));
780 err = out->set(format, channels, sampleRate, devices);
781 if(err == NO_ERROR) {
782 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -0700783 ALOGD("openoutput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700784 }
785 if (status) *status = err;
786 return out;
787 } else
788#endif
789 {
790
791 alsa_handle_t alsa_handle;
792 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
793
794 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
795 bufferSize &= ~b;
796
797 alsa_handle.module = mALSADevice;
798 alsa_handle.bufferSize = bufferSize;
799 alsa_handle.devices = devices;
800 alsa_handle.handle = 0;
801 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
802 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
803 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
804 alsa_handle.latency = PLAYBACK_LATENCY;
805 alsa_handle.rxHandle = 0;
806 alsa_handle.ucMgr = mUcMgr;
807
808 char *use_case;
809 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
810 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
811 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
812 } else {
813 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
814 }
815 free(use_case);
816 mDeviceList.push_back(alsa_handle);
817 ALSAHandleList::iterator it = mDeviceList.end();
818 it--;
Ajay Dudani8a9785b2012-09-10 23:28:45 -0700819 ALOGV("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700820#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700821 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
822 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700823 ALOGE("Routing to proxy for normal playback in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700824 devices |= AudioSystem::DEVICE_OUT_PROXY;
825 }
826#endif
827 mALSADevice->route(&(*it), devices, mode());
828 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
829 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
830 } else {
831 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
832 }
833 err = mALSADevice->open(&(*it));
834 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700835 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700836 } else {
837 out = new AudioStreamOutALSA(this, &(*it));
838 err = out->set(format, channels, sampleRate, devices);
839 }
840
841 if (status) *status = err;
842 return out;
843 }
844}
845
846void
847AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
848{
849 delete out;
850}
851
Ajay Dudani9746c472012-06-18 16:01:16 -0700852#ifdef QCOM_TUNNEL_LPA_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700853AudioStreamOut *
854AudioHardwareALSA::openOutputSession(uint32_t devices,
855 int *format,
856 status_t *status,
857 int sessionId,
858 uint32_t samplingRate,
859 uint32_t channels)
860{
861 Mutex::Autolock autoLock(mLock);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700862 ALOGD("openOutputSession = %d" ,sessionId);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700863 AudioStreamOutALSA *out = 0;
864 status_t err = BAD_VALUE;
865
866 alsa_handle_t alsa_handle;
867 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
868
869 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
870 bufferSize &= ~b;
871
872 alsa_handle.module = mALSADevice;
873 alsa_handle.bufferSize = bufferSize;
874 alsa_handle.devices = devices;
875 alsa_handle.handle = 0;
876 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
877 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
878 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
879 alsa_handle.latency = VOICE_LATENCY;
880 alsa_handle.rxHandle = 0;
881 alsa_handle.ucMgr = mUcMgr;
882
883 char *use_case;
884 if(sessionId == TUNNEL_SESSION_ID) {
885 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
886 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
887 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, sizeof(alsa_handle.useCase));
888 } else {
889 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, sizeof(alsa_handle.useCase));
890 }
891 } else {
892 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
893 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
894 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, sizeof(alsa_handle.useCase));
895 } else {
896 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LPA, sizeof(alsa_handle.useCase));
897 }
898 }
899 free(use_case);
900 mDeviceList.push_back(alsa_handle);
901 ALSAHandleList::iterator it = mDeviceList.end();
902 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700903 ALOGD("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700904#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700905 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
906 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700907 ALOGE("Routing to proxy for LPA in openOutputSession");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700908 devices |= AudioSystem::DEVICE_OUT_PROXY;
909 mALSADevice->route(&(*it), devices, mode());
910 devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700911 ALOGD("Starting USBPlayback for LPA");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700912 startUsbPlaybackIfNotStarted();
913 musbPlaybackState |= USBPLAYBACKBIT_LPA;
914 } else
915#endif
916 {
917 mALSADevice->route(&(*it), devices, mode());
918 }
919 if(sessionId == TUNNEL_SESSION_ID) {
920 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) {
921 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_TUNNEL);
922 } else {
923 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_TUNNEL);
924 }
925 }
926 else {
927 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) {
928 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOW_POWER);
929 } else {
930 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LPA);
931 }
932 }
933 err = mALSADevice->open(&(*it));
934 out = new AudioStreamOutALSA(this, &(*it));
935
936 if (status) *status = err;
937 return out;
938}
939
940void
941AudioHardwareALSA::closeOutputSession(AudioStreamOut* out)
942{
943 delete out;
944}
Ajay Dudani9746c472012-06-18 16:01:16 -0700945#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700946
947AudioStreamIn *
948AudioHardwareALSA::openInputStream(uint32_t devices,
949 int *format,
950 uint32_t *channels,
951 uint32_t *sampleRate,
952 status_t *status,
953 AudioSystem::audio_in_acoustics acoustics)
954{
955 Mutex::Autolock autoLock(mLock);
956 char *use_case;
957 int newMode = mode();
958 uint32_t route_devices;
959
960 status_t err = BAD_VALUE;
961 AudioStreamInALSA *in = 0;
962 ALSAHandleList::iterator it;
963
Iliyan Malchev4113f342012-06-11 14:39:47 -0700964 ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700965 if (devices & (devices - 1)) {
966 if (status) *status = err;
967 return in;
968 }
969
970 if((devices == AudioSystem::DEVICE_IN_COMMUNICATION) &&
971 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
972 bool voipstream_active = false;
973 for(it = mDeviceList.begin();
974 it != mDeviceList.end(); ++it) {
975 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
976 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700977 ALOGD("openInput: it->rxHandle %p it->handle %p",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700978 voipstream_active = true;
979 break;
980 }
981 }
982 if(voipstream_active == false) {
983 mVoipStreamCount = 0;
984 mVoipMicMute = false;
985 alsa_handle_t alsa_handle;
986 unsigned long bufferSize;
987 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
988 bufferSize = VOIP_BUFFER_SIZE_8K;
989 }
990 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
991 bufferSize = VOIP_BUFFER_SIZE_16K;
992 }
993 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700994 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700995 if (status) *status = err;
996 return in;
997 }
998 alsa_handle.module = mALSADevice;
999 alsa_handle.bufferSize = bufferSize;
1000 alsa_handle.devices = devices;
1001 alsa_handle.handle = 0;
1002 if(*format == AudioSystem::PCM_16_BIT)
1003 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1004 else
1005 alsa_handle.format = *format;
1006 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
1007 alsa_handle.sampleRate = *sampleRate;
1008 alsa_handle.latency = VOIP_RECORD_LATENCY;
1009 alsa_handle.rxHandle = 0;
1010 alsa_handle.ucMgr = mUcMgr;
1011 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
1012 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1013 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1014 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
1015 } else {
1016 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
1017 }
1018 free(use_case);
1019 mDeviceList.push_back(alsa_handle);
1020 it = mDeviceList.end();
1021 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001022 ALOGE("mCurrDevice: %d", mCurDevice);
Ajay Dudani9746c472012-06-18 16:01:16 -07001023#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001024 if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1025 (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001026 ALOGE("Routing everything from proxy for voipcall");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001027 mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -07001028 ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001029 startUsbPlaybackIfNotStarted();
1030 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001031 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001032 startUsbRecordingIfNotStarted();
1033 musbRecordingState |= USBRECBIT_VOIPCALL;
1034 }else
1035#endif
1036 {
1037 mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
1038 }
1039 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
1040 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
1041 } else {
1042 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
1043 }
1044 if(sampleRate) {
1045 it->sampleRate = *sampleRate;
1046 }
1047 if(channels)
1048 it->channels = AudioSystem::popCount(*channels);
1049 err = mALSADevice->startVoipCall(&(*it));
1050 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001051 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001052 return NULL;
1053 }
1054 }
1055 in = new AudioStreamInALSA(this, &(*it), acoustics);
1056 err = in->set(format, channels, sampleRate, devices);
1057 if(err == NO_ERROR) {
1058 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -07001059 ALOGD("OpenInput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001060 }
Iliyan Malchev4113f342012-06-11 14:39:47 -07001061 ALOGE("openInput: After Get alsahandle");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001062 if (status) *status = err;
1063 return in;
1064 } else
1065 {
1066 for(ALSAHandleList::iterator itDev = mDeviceList.begin();
1067 itDev != mDeviceList.end(); ++itDev)
1068 {
1069 if((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_HIFI_REC, MAX_UC_LEN))
1070 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, MAX_UC_LEN))
1071 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_FM, MAX_UC_LEN))
Ajay Dudani9746c472012-06-18 16:01:16 -07001072#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001073 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_REC, MAX_UC_LEN))
1074#endif
1075 )
1076 {
Ajay Dudani9746c472012-06-18 16:01:16 -07001077#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001078 if(!(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001079 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001080 itDev->useCase, itDev->devices, itDev->module);
1081 return in;
1082 }
1083#endif
1084 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001085#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001086 else if ((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, MAX_UC_LEN))
1087 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, MAX_UC_LEN)))
1088 {
1089 if((devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001090 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001091 itDev->useCase, itDev->devices, itDev->module);
1092 return in;
1093 }
1094 }
1095#endif
1096 }
1097
1098 alsa_handle_t alsa_handle;
1099 unsigned long bufferSize = DEFAULT_IN_BUFFER_SIZE;
1100
1101 alsa_handle.module = mALSADevice;
1102 alsa_handle.bufferSize = bufferSize;
1103 alsa_handle.devices = devices;
1104 alsa_handle.handle = 0;
1105 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1106 alsa_handle.channels = VOICE_CHANNEL_MODE;
1107 alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
1108 alsa_handle.latency = RECORD_LATENCY;
1109 alsa_handle.rxHandle = 0;
1110 alsa_handle.ucMgr = mUcMgr;
1111 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1112 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1113 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1114 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001115 ALOGD("openInputStream: into incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001116 mIncallMode = *channels;
1117 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1118 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1119 if (mFusion3Platform) {
1120 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1121 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1122 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001123 } else {
1124 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
1125 sizeof(alsa_handle.useCase));
1126 }
1127 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1128 if (mFusion3Platform) {
1129 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1130 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1131 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001132 } else {
1133 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
1134 sizeof(alsa_handle.useCase));
1135 }
1136 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001137#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001138 } else if((devices == AudioSystem::DEVICE_IN_FM_RX)) {
1139 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(alsa_handle.useCase));
1140 } else if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1141 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
1142#endif
1143 } else {
1144 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(alsa_handle.useCase));
1145 }
1146 } else {
1147 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1148 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001149 ALOGD("openInputStream: incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001150 mIncallMode = *channels;
1151 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1152 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1153 if (mFusion3Platform) {
1154 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1155 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1156 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001157 } else {
1158 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
1159 sizeof(alsa_handle.useCase));
1160 }
1161 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1162 if (mFusion3Platform) {
1163 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1164 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1165 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001166 } else {
1167 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
1168 sizeof(alsa_handle.useCase));
1169 }
1170 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001171#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001172 } else if(devices == AudioSystem::DEVICE_IN_FM_RX) {
1173 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_REC, sizeof(alsa_handle.useCase));
1174 } else if (devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1175 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(alsa_handle.useCase));
1176#endif
1177 } else {
1178 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
1179 }
1180 }
1181 free(use_case);
1182 mDeviceList.push_back(alsa_handle);
1183 ALSAHandleList::iterator it = mDeviceList.end();
1184 it--;
1185 //update channel info before do routing
1186 if(channels) {
1187 it->channels = AudioSystem::popCount((*channels) &
Ajay Dudani9746c472012-06-18 16:01:16 -07001188 (AudioSystem::CHANNEL_IN_STEREO
1189 | AudioSystem::CHANNEL_IN_MONO
1190#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001191 | AudioSystem::CHANNEL_IN_5POINT1
1192#endif
1193 ));
Iliyan Malchev4113f342012-06-11 14:39:47 -07001194 ALOGV("updated channel info: channels=%d", it->channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001195 }
1196 if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
1197 /* Add current devices info to devices to do route */
Ajay Dudani9746c472012-06-18 16:01:16 -07001198#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001199 if(mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
1200 mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001201 ALOGD("Routing everything from proxy for VOIP call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001202 route_devices = devices | AudioSystem::DEVICE_IN_PROXY;
1203 } else
1204#endif
1205 {
1206 route_devices = devices | mCurDevice;
1207 }
1208 mALSADevice->route(&(*it), route_devices, mode());
1209 } else {
Ajay Dudani9746c472012-06-18 16:01:16 -07001210#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001211 if(devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET ||
1212 devices & AudioSystem::DEVICE_IN_PROXY) {
1213 devices |= AudioSystem::DEVICE_IN_PROXY;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001214 ALOGE("routing everything from proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001215 mALSADevice->route(&(*it), devices, mode());
1216 } else
1217#endif
1218 {
1219 mALSADevice->route(&(*it), devices, mode());
1220 }
1221 }
1222
1223 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
Ajay Dudani9746c472012-06-18 16:01:16 -07001224#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001225 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) ||
1226 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
1227#endif
1228 !strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) ||
1229 !strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
1230 !strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
1231 snd_use_case_set(mUcMgr, "_verb", it->useCase);
1232 } else {
1233 snd_use_case_set(mUcMgr, "_enamod", it->useCase);
1234 }
1235 if(sampleRate) {
1236 it->sampleRate = *sampleRate;
1237 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001238#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001239 if (6 == it->channels) {
1240 if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
1241 || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001242 ALOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001243 it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
1244 }
1245 }
1246#endif
1247 err = mALSADevice->open(&(*it));
1248 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001249 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001250 } else {
1251 in = new AudioStreamInALSA(this, &(*it), acoustics);
1252 err = in->set(format, channels, sampleRate, devices);
1253 }
1254 if (status) *status = err;
1255 return in;
1256 }
1257}
1258
1259void
1260AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
1261{
1262 delete in;
1263}
1264
1265status_t AudioHardwareALSA::setMicMute(bool state)
1266{
1267 int newMode = mode();
Iliyan Malchev4113f342012-06-11 14:39:47 -07001268 ALOGD("setMicMute newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001269 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1270 if (mVoipMicMute != state) {
1271 mVoipMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001272 ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001273 if(mALSADevice) {
1274 mALSADevice->setVoipMicMute(state);
1275 }
1276 }
1277 } else {
1278 if (mMicMute != state) {
1279 mMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001280 ALOGD("setMicMute: mMicMute %d", mMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001281 if(mALSADevice) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001282 if(mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001283 mALSADevice->setMicMute(state);
Ajay Dudani9746c472012-06-18 16:01:16 -07001284 if(mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001285 mALSADevice->setVoLTEMicMute(state);
1286 }
1287 }
1288 }
1289 return NO_ERROR;
1290}
1291
1292status_t AudioHardwareALSA::getMicMute(bool *state)
1293{
1294 int newMode = mode();
1295 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1296 *state = mVoipMicMute;
1297 } else {
1298 *state = mMicMute;
1299 }
1300 return NO_ERROR;
1301}
1302
1303status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
1304{
1305 return NO_ERROR;
1306}
1307
1308size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
1309{
1310 size_t bufferSize;
1311 if (format != AudioSystem::PCM_16_BIT
1312 && format != AudioSystem::AMR_NB
1313 && format != AudioSystem::AMR_WB
Ajay Dudani9746c472012-06-18 16:01:16 -07001314#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001315 && format != AudioSystem::EVRC
1316 && format != AudioSystem::EVRCB
Ajay Dudani9746c472012-06-18 16:01:16 -07001317 && format != AudioSystem::EVRCWB
1318#endif
1319 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001320 ALOGW("getInputBufferSize bad format: %d", format);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001321 return 0;
1322 }
1323 if(sampleRate == 16000) {
1324 bufferSize = DEFAULT_IN_BUFFER_SIZE * 2 * channelCount;
1325 } else if(sampleRate < 44100) {
1326 bufferSize = DEFAULT_IN_BUFFER_SIZE * channelCount;
1327 } else {
1328 bufferSize = DEFAULT_IN_BUFFER_SIZE * 12;
1329 }
1330 return bufferSize;
1331}
1332
Ajay Dudani9746c472012-06-18 16:01:16 -07001333#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001334void AudioHardwareALSA::handleFm(int device)
1335{
1336int newMode = mode();
1337 if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
1338 // Start FM Radio on current active device
1339 unsigned long bufferSize = FM_BUFFER_SIZE;
1340 alsa_handle_t alsa_handle;
1341 char *use_case;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001342 ALOGV("Start FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001343 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1344 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1345 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, sizeof(alsa_handle.useCase));
1346 } else {
1347 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_FM, sizeof(alsa_handle.useCase));
1348 }
1349 free(use_case);
1350
1351 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1352 bufferSize &= ~b;
1353 alsa_handle.module = mALSADevice;
1354 alsa_handle.bufferSize = bufferSize;
1355 alsa_handle.devices = device;
1356 alsa_handle.handle = 0;
1357 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1358 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
1359 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
1360 alsa_handle.latency = VOICE_LATENCY;
1361 alsa_handle.rxHandle = 0;
1362 alsa_handle.ucMgr = mUcMgr;
1363 mIsFmActive = 1;
1364 mDeviceList.push_back(alsa_handle);
1365 ALSAHandleList::iterator it = mDeviceList.end();
1366 it--;
1367 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1368 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1369 device |= AudioSystem::DEVICE_OUT_PROXY;
1370 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001371 ALOGE("Routing to proxy for FM case");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001372 }
1373 mALSADevice->route(&(*it), (uint32_t)device, newMode);
1374 if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) {
1375 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_DIGITAL_RADIO);
1376 } else {
1377 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
1378 }
1379 mALSADevice->startFm(&(*it));
1380 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1381 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001382 ALOGE("Starting FM, musbPlaybackState %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001383 startUsbPlaybackIfNotStarted();
1384 musbPlaybackState |= USBPLAYBACKBIT_FM;
1385 }
1386 } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
1387 //i Stop FM Radio
Iliyan Malchev4113f342012-06-11 14:39:47 -07001388 ALOGV("Stop FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001389 for(ALSAHandleList::iterator it = mDeviceList.begin();
1390 it != mDeviceList.end(); ++it) {
1391 if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
1392 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
1393 mALSADevice->close(&(*it));
1394 //mALSADevice->route(&(*it), (uint32_t)device, newMode);
1395 mDeviceList.erase(it);
1396 break;
1397 }
1398 }
1399 mIsFmActive = 0;
1400 musbPlaybackState &= ~USBPLAYBACKBIT_FM;
1401 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1402 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1403 closeUsbPlaybackIfNothingActive();
1404 }
1405 }
1406}
1407#endif
1408
1409void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, int device)
1410{
1411 for(ALSAHandleList::iterator it = mDeviceList.begin();
1412 it != mDeviceList.end(); ++it) {
1413 if((!strcmp(it->useCase, verb)) ||
1414 (!strcmp(it->useCase, modifier))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001415 ALOGV("Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001416 mALSADevice->close(&(*it));
1417 mALSADevice->route(&(*it), (uint32_t)device, mode);
1418 mDeviceList.erase(it);
1419 break;
1420 }
1421 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001422#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001423 if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001424 ALOGE("Voice call ended on USB");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001425 musbPlaybackState &= ~USBPLAYBACKBIT_VOICECALL;
1426 musbRecordingState &= ~USBRECBIT_VOICECALL;
1427 closeUsbRecordingIfNothingActive();
1428 closeUsbPlaybackIfNothingActive();
1429 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001430#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001431}
1432void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, int device)
1433{
1434// Start voice call
1435unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
1436alsa_handle_t alsa_handle;
1437char *use_case;
1438 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1439 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1440 strlcpy(alsa_handle.useCase, verb, sizeof(alsa_handle.useCase));
1441 } else {
1442 strlcpy(alsa_handle.useCase, modifier, sizeof(alsa_handle.useCase));
1443 }
1444 free(use_case);
1445
1446 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1447 bufferSize &= ~b;
1448 alsa_handle.module = mALSADevice;
1449 alsa_handle.bufferSize = bufferSize;
1450 alsa_handle.devices = device;
1451 alsa_handle.handle = 0;
1452 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1453 alsa_handle.channels = VOICE_CHANNEL_MODE;
1454 alsa_handle.sampleRate = VOICE_SAMPLING_RATE;
1455 alsa_handle.latency = VOICE_LATENCY;
1456 alsa_handle.rxHandle = 0;
1457 alsa_handle.ucMgr = mUcMgr;
1458 mDeviceList.push_back(alsa_handle);
1459 ALSAHandleList::iterator it = mDeviceList.end();
1460 it--;
Ajay Dudani9746c472012-06-18 16:01:16 -07001461#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001462 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1463 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1464 device |= AudioSystem::DEVICE_OUT_PROXY;
1465 alsa_handle.devices = device;
1466 }
1467#endif
1468 mALSADevice->route(&(*it), (uint32_t)device, mode);
1469 if (!strcmp(it->useCase, verb)) {
1470 snd_use_case_set(mUcMgr, "_verb", verb);
1471 } else {
1472 snd_use_case_set(mUcMgr, "_enamod", modifier);
1473 }
1474 mALSADevice->startVoiceCall(&(*it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001475#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001476 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1477 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1478 startUsbRecordingIfNotStarted();
1479 startUsbPlaybackIfNotStarted();
1480 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
1481 musbRecordingState |= USBRECBIT_VOICECALL;
1482 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001483#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001484}
1485
1486bool AudioHardwareALSA::routeVoiceCall(int device, int newMode)
1487{
1488int csCallState = mCallState&0xF;
1489 bool isRouted = false;
1490 switch (csCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001491 case CS_INACTIVE:
1492 if (mCSCallActive != CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001493 ALOGD("doRouting: Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001494 disableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1495 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1496 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001497 mCSCallActive = CS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001498 }
1499 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001500 case CS_ACTIVE:
1501 if (mCSCallActive == CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001502 ALOGD("doRouting: Enabling CS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001503 enableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1504 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1505 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001506 mCSCallActive = CS_ACTIVE;
1507 } else if (mCSCallActive == CS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001508 ALOGD("doRouting: Resume voice call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001509 ALSAHandleList::iterator vt_it;
1510 for(vt_it = mDeviceList.begin();
1511 vt_it != mDeviceList.end(); ++vt_it) {
1512 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1513 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1514 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1515 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
1516 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001517 mCSCallActive = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001518 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001519 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001520 break;
1521 }
1522 }
1523 }
1524 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001525 case CS_HOLD:
1526 if (mCSCallActive == CS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001527 ALOGD("doRouting: Voice call going to Hold");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001528 ALSAHandleList::iterator vt_it;
1529 for(vt_it = mDeviceList.begin();
1530 vt_it != mDeviceList.end(); ++vt_it) {
1531 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1532 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1533 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1534 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001535 mCSCallActive = CS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001536 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1537 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001538 ALOGE("Voice pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001539 break;
1540 }
1541 }
1542 }
1543 break;
1544 }
1545 return isRouted;
1546}
1547bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
1548{
1549int volteCallState = mCallState&0xF0;
1550bool isRouted = false;
1551switch (volteCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001552 case IMS_INACTIVE:
1553 if (mVolteCallActive != IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001554 ALOGD("doRouting: Disabling IMS call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001555 disableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1556 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1557 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001558 mVolteCallActive = IMS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001559 }
1560 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001561 case IMS_ACTIVE:
1562 if (mVolteCallActive == IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001563 ALOGD("doRouting: Enabling IMS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001564 enableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1565 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1566 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001567 mVolteCallActive = IMS_ACTIVE;
1568 } else if (mVolteCallActive == IMS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001569 ALOGD("doRouting: Resume IMS call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001570 ALSAHandleList::iterator vt_it;
1571 for(vt_it = mDeviceList.begin();
1572 vt_it != mDeviceList.end(); ++vt_it) {
1573 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1574 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1575 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1576 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
1577 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001578 mVolteCallActive = IMS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001579 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001580 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001581 break;
1582 }
1583 }
1584 }
1585 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001586 case IMS_HOLD:
1587 if (mVolteCallActive == IMS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001588 ALOGD("doRouting: IMS ACTIVE going to HOLD");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001589 ALSAHandleList::iterator vt_it;
1590 for(vt_it = mDeviceList.begin();
1591 vt_it != mDeviceList.end(); ++vt_it) {
1592 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1593 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1594 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1595 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001596 mVolteCallActive = IMS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001597 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1598 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001599 ALOGE("VoLTE Pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001600 break;
1601 }
1602 }
1603 }
1604 break;
1605 }
1606 return isRouted;
1607}
1608
1609} // namespace android_audio_legacy