blob: 7343c63dcf12c5c545ca85f22951246797e04962 [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) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700169 ALOGD("closing ucm instance: %u", (unsigned)mUcMgr);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700170 snd_use_case_mgr_close(mUcMgr);
171 }
172 if (mALSADevice) {
173 mALSADevice->common.close(&mALSADevice->common);
174 }
175 for(ALSAHandleList::iterator it = mDeviceList.begin();
176 it != mDeviceList.end(); ++it) {
177 it->useCase[0] = 0;
178 mDeviceList.erase(it);
179 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700180#ifdef QCOM_ACDB_ENABLED
181 acdb_loader_deallocate_ACDB();
182#endif
183#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700184 delete mAudioUsbALSA;
Ajay Dudani9746c472012-06-18 16:01:16 -0700185#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700186}
187
188status_t AudioHardwareALSA::initCheck()
189{
190 if (!mALSADevice)
191 return NO_INIT;
192
193 return NO_ERROR;
194}
195
196status_t AudioHardwareALSA::setVoiceVolume(float v)
197{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700198 ALOGD("setVoiceVolume(%f)\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700199 if (v < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700200 ALOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700201 v = 0.0;
202 } else if (v > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700203 ALOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700204 v = 1.0;
205 }
206
207 int newMode = mode();
Iliyan Malchev4113f342012-06-11 14:39:47 -0700208 ALOGD("setVoiceVolume newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700209 int vol = lrint(v * 100.0);
210
211 // Voice volume levels from android are mapped to driver volume levels as follows.
212 // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
213 // So adjust the volume to get the correct volume index in driver
214 vol = 100 - vol;
215
216 if (mALSADevice) {
217 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
218 mALSADevice->setVoipVolume(vol);
219 } else if (newMode == AudioSystem::MODE_IN_CALL){
Ajay Dudani9746c472012-06-18 16:01:16 -0700220 if (mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700221 mALSADevice->setVoiceVolume(vol);
Ajay Dudani9746c472012-06-18 16:01:16 -0700222 if (mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700223 mALSADevice->setVoLTEVolume(vol);
224 }
225 }
226
227 return NO_ERROR;
228}
229
Ajay Dudani9746c472012-06-18 16:01:16 -0700230#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700231status_t AudioHardwareALSA::setFmVolume(float value)
232{
233 status_t status = NO_ERROR;
234
235 int vol;
236
237 if (value < 0.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700238 ALOGW("setFmVolume(%f) under 0.0, assuming 0.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700239 value = 0.0;
240 } else if (value > 1.0) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700241 ALOGW("setFmVolume(%f) over 1.0, assuming 1.0\n", value);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700242 value = 1.0;
243 }
244 vol = lrint((value * 0x2000) + 0.5);
245
Iliyan Malchev4113f342012-06-11 14:39:47 -0700246 ALOGD("setFmVolume(%f)\n", value);
247 ALOGD("Setting FM volume to %d (available range is 0 to 0x2000)\n", vol);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700248
249 mALSADevice->setFmVolume(vol);
250
251 return status;
252}
253#endif
254
255status_t AudioHardwareALSA::setMasterVolume(float volume)
256{
257 return NO_ERROR;
258}
259
260status_t AudioHardwareALSA::setMode(int mode)
261{
262 status_t status = NO_ERROR;
263
264 if (mode != mMode) {
265 status = AudioHardwareBase::setMode(mode);
266 }
267
268 if (mode == AudioSystem::MODE_IN_CALL) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700269 mCallState = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -0700270 }else if (mode == AudioSystem::MODE_NORMAL) {
271 mCallState = 0;
272 }
273
274 return status;
275}
276
277status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs)
278{
279 AudioParameter param = AudioParameter(keyValuePairs);
280 String8 key;
281 String8 value;
282 status_t status = NO_ERROR;
283 int device;
284 int btRate;
285 int state;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700286 ALOGD("setParameters() %s", keyValuePairs.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700287
288 key = String8(TTY_MODE_KEY);
289 if (param.get(key, value) == NO_ERROR) {
290 mDevSettingsFlag &= TTY_CLEAR;
ty.leea97e6f62012-08-15 10:11:50 +0900291 if (value == "tty_full") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700292 mDevSettingsFlag |= TTY_FULL;
ty.leea97e6f62012-08-15 10:11:50 +0900293 } else if (value == "tty_hco") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700294 mDevSettingsFlag |= TTY_HCO;
ty.leea97e6f62012-08-15 10:11:50 +0900295 } else if (value == "tty_vco") {
Iliyan Malchev4765c432012-06-11 14:36:16 -0700296 mDevSettingsFlag |= TTY_VCO;
297 } else {
298 mDevSettingsFlag |= TTY_OFF;
299 }
Iliyan Malchev4113f342012-06-11 14:39:47 -0700300 ALOGI("Changed TTY Mode=%s", value.string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700301 mALSADevice->setFlags(mDevSettingsFlag);
302 if(mMode != AudioSystem::MODE_IN_CALL){
303 return NO_ERROR;
304 }
305 doRouting(0);
306 }
307
308 key = String8(FLUENCE_KEY);
309 if (param.get(key, value) == NO_ERROR) {
310 if (value == "quadmic") {
311 mDevSettingsFlag |= QMIC_FLAG;
312 mDevSettingsFlag &= (~DMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700313 ALOGV("Fluence quadMic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700314 } else if (value == "dualmic") {
315 mDevSettingsFlag |= DMIC_FLAG;
316 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700317 ALOGV("Fluence dualmic feature Enabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700318 } else if (value == "none") {
319 mDevSettingsFlag &= (~DMIC_FLAG);
320 mDevSettingsFlag &= (~QMIC_FLAG);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700321 ALOGV("Fluence feature Disabled");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700322 }
323 mALSADevice->setFlags(mDevSettingsFlag);
324 doRouting(0);
325 }
326
Ajay Dudani9746c472012-06-18 16:01:16 -0700327#ifdef QCOM_CSDCLIENT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700328 if (mFusion3Platform) {
329 key = String8(INCALLMUSIC_KEY);
330 if (param.get(key, value) == NO_ERROR) {
331 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700332 ALOGV("Enabling Incall Music setting in the setparameter\n");
Ajay Dudani9746c472012-06-18 16:01:16 -0700333 csd_client_start_playback();
Iliyan Malchev4765c432012-06-11 14:36:16 -0700334 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700335 ALOGV("Disabling Incall Music setting in the setparameter\n");
Ajay Dudani9746c472012-06-18 16:01:16 -0700336 csd_client_stop_playback();
Iliyan Malchev4765c432012-06-11 14:36:16 -0700337 }
338 }
339 }
Ajay Dudani9746c472012-06-18 16:01:16 -0700340#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700341
342 key = String8(ANC_KEY);
343 if (param.get(key, value) == NO_ERROR) {
344 if (value == "true") {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700345 ALOGV("Enabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700346 mDevSettingsFlag |= ANC_FLAG;
347 } else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700348 ALOGV("Disabling ANC setting in the setparameter\n");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700349 mDevSettingsFlag &= (~ANC_FLAG);
350 }
351 mALSADevice->setFlags(mDevSettingsFlag);
352 doRouting(0);
353 }
354
355 key = String8(AudioParameter::keyRouting);
356 if (param.getInt(key, device) == NO_ERROR) {
357 // Ignore routing if device is 0.
358 if(device) {
359 doRouting(device);
360 }
361 param.remove(key);
362 }
363
364 key = String8(BT_SAMPLERATE_KEY);
365 if (param.getInt(key, btRate) == NO_ERROR) {
366 mALSADevice->setBtscoRate(btRate);
367 param.remove(key);
368 }
369
370 key = String8(BTHEADSET_VGS);
371 if (param.get(key, value) == NO_ERROR) {
372 if (value == "on") {
373 mBluetoothVGS = true;
374 } else {
375 mBluetoothVGS = false;
376 }
377 }
378
379 key = String8(WIDEVOICE_KEY);
380 if (param.get(key, value) == NO_ERROR) {
381 bool flag = false;
382 if (value == "true") {
383 flag = true;
384 }
385 if(mALSADevice) {
386 mALSADevice->enableWideVoice(flag);
387 }
388 param.remove(key);
389 }
390
391 key = String8(VOIPRATE_KEY);
392 if (param.get(key, value) == NO_ERROR) {
393 mVoipBitRate = atoi(value);
394 param.remove(key);
395 }
396
397 key = String8(FENS_KEY);
398 if (param.get(key, value) == NO_ERROR) {
399 bool flag = false;
400 if (value == "true") {
401 flag = true;
402 }
403 if(mALSADevice) {
404 mALSADevice->enableFENS(flag);
405 }
406 param.remove(key);
407 }
408
Ajay Dudani9746c472012-06-18 16:01:16 -0700409#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700410 key = String8(AudioParameter::keyHandleFm);
411 if (param.getInt(key, device) == NO_ERROR) {
412 // Ignore if device is 0
413 if(device) {
414 handleFm(device);
415 }
416 param.remove(key);
417 }
418#endif
419
420 key = String8(ST_KEY);
421 if (param.get(key, value) == NO_ERROR) {
422 bool flag = false;
423 if (value == "true") {
424 flag = true;
425 }
426 if(mALSADevice) {
427 mALSADevice->enableSlowTalk(flag);
428 }
429 param.remove(key);
430 }
431 key = String8(MODE_CALL_KEY);
432 if (param.getInt(key,state) == NO_ERROR) {
433 if (mCallState != state) {
434 mCallState = state;
435 doRouting(0);
436 }
437 mCallState = state;
438 }
439 if (param.size()) {
440 status = BAD_VALUE;
441 }
442 return status;
443}
444
445String8 AudioHardwareALSA::getParameters(const String8& keys)
446{
447 AudioParameter param = AudioParameter(keys);
448 String8 value;
449
450 String8 key = String8(DUALMIC_KEY);
451 if (param.get(key, value) == NO_ERROR) {
452 value = String8("false");
453 param.add(key, value);
454 }
455
456 key = String8(FLUENCE_KEY);
457 if (param.get(key, value) == NO_ERROR) {
458 if ((mDevSettingsFlag & QMIC_FLAG) &&
459 (mDevSettingsFlag & ~DMIC_FLAG))
460 value = String8("quadmic");
461 else if ((mDevSettingsFlag & DMIC_FLAG) &&
462 (mDevSettingsFlag & ~QMIC_FLAG))
463 value = String8("dualmic");
464 else if ((mDevSettingsFlag & ~DMIC_FLAG) &&
465 (mDevSettingsFlag & ~QMIC_FLAG))
466 value = String8("none");
467 param.add(key, value);
468 }
469
Ajay Dudani9746c472012-06-18 16:01:16 -0700470#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700471 key = String8("Fm-radio");
472 if ( param.get(key,value) == NO_ERROR ) {
473 if ( mIsFmActive ) {
474 param.addInt(String8("isFMON"), true );
475 }
476 }
477#endif
478
479 key = String8(BTHEADSET_VGS);
480 if (param.get(key, value) == NO_ERROR) {
481 if(mBluetoothVGS)
482 param.addInt(String8("isVGS"), true);
483 }
484
Iliyan Malchev4113f342012-06-11 14:39:47 -0700485 ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700486 return param.toString();
487}
488
Ajay Dudani9746c472012-06-18 16:01:16 -0700489#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700490void AudioHardwareALSA::closeUSBPlayback()
491{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700492 ALOGV("closeUSBPlayback, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700493 musbPlaybackState = 0;
494 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_KILLTHREAD);
495}
496
497void AudioHardwareALSA::closeUSBRecording()
498{
Iliyan Malchev4113f342012-06-11 14:39:47 -0700499 ALOGV("closeUSBRecording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700500 musbRecordingState = 0;
501 mAudioUsbALSA->exitRecordingThread(SIGNAL_EVENT_KILLTHREAD);
502}
503
504void AudioHardwareALSA::closeUsbPlaybackIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700505 ALOGV("closeUsbPlaybackIfNothingActive, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700506 if(!musbPlaybackState && mAudioUsbALSA != NULL) {
507 mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_TIMEOUT);
508 }
509}
510
511void AudioHardwareALSA::closeUsbRecordingIfNothingActive(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700512 ALOGV("closeUsbRecordingIfNothingActive, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700513 if(!musbRecordingState && mAudioUsbALSA != NULL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700514 ALOGD("Closing USB Recording Session as no stream is active");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700515 mAudioUsbALSA->setkillUsbRecordingThread(true);
516 }
517}
518
519void AudioHardwareALSA::startUsbPlaybackIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700520 ALOGV("Starting the USB playback %d kill %d", musbPlaybackState,
Iliyan Malchev4765c432012-06-11 14:36:16 -0700521 mAudioUsbALSA->getkillUsbPlaybackThread());
522 if((!musbPlaybackState) || (mAudioUsbALSA->getkillUsbPlaybackThread() == true)) {
523 mAudioUsbALSA->startPlayback();
524 }
525}
526
527void AudioHardwareALSA::startUsbRecordingIfNotStarted(){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700528 ALOGV("Starting the recording musbRecordingState: %d killUsbRecordingThread %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700529 musbRecordingState, mAudioUsbALSA->getkillUsbRecordingThread());
530 if((!musbRecordingState) || (mAudioUsbALSA->getkillUsbRecordingThread() == true)) {
531 mAudioUsbALSA->startRecording();
532 }
533}
Ajay Dudani9746c472012-06-18 16:01:16 -0700534#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700535
536void AudioHardwareALSA::doRouting(int device)
537{
538 Mutex::Autolock autoLock(mLock);
539 int newMode = mode();
540 bool isRouted = false;
541
Ajay Dudani9746c472012-06-18 16:01:16 -0700542 if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
543#ifdef QCOM_FM_ENABLED
544 || (device == AudioSystem::DEVICE_IN_FM_RX)
545 || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT)
546 || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
Iliyan Malchev4765c432012-06-11 14:36:16 -0700547#endif
Ajay Dudani9746c472012-06-18 16:01:16 -0700548 || (device == AudioSystem::DEVICE_IN_COMMUNICATION)
549 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700550 ALOGV("Ignoring routing for FM/INCALL/VOIP recording");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700551 return;
552 }
553 if (device == 0)
554 device = mCurDevice;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700555 ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
Iliyan Malchev4765c432012-06-11 14:36:16 -0700556 "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
557 mIsFmActive);
558
559 isRouted = routeVoLTECall(device, newMode);
560 isRouted |= routeVoiceCall(device, newMode);
561
562 if(!isRouted) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700563#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700564 if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
565 !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
566 !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
567 (musbPlaybackState)){
568 //USB unplugged
569 device &= ~ AudioSystem::DEVICE_OUT_PROXY;
570 device &= ~ AudioSystem::DEVICE_IN_PROXY;
571 ALSAHandleList::iterator it = mDeviceList.end();
572 it--;
573 mALSADevice->route(&(*it), (uint32_t)device, newMode);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700574 ALOGE("USB UNPLUGGED, setting musbPlaybackState to 0");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700575 musbPlaybackState = 0;
576 musbRecordingState = 0;
577 closeUSBRecording();
578 closeUSBPlayback();
579 } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
580 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700581 ALOGE("Routing everything to prox now");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700582 ALSAHandleList::iterator it = mDeviceList.end();
583 it--;
584 mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
585 newMode);
586 for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
587 if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
588 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700589 ALOGD("doRouting: LPA device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700590 startUsbPlaybackIfNotStarted();
591 musbPlaybackState |= USBPLAYBACKBIT_LPA;
592 break;
593 } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
594 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700595 ALOGD("doRouting: VOICE device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700596 startUsbRecordingIfNotStarted();
597 startUsbPlaybackIfNotStarted();
598 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
599 musbRecordingState |= USBPLAYBACKBIT_VOICECALL;
600 break;
601 }else if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
602 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700603 ALOGD("doRouting: FM device switch to proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700604 startUsbPlaybackIfNotStarted();
605 musbPlaybackState |= USBPLAYBACKBIT_FM;
606 break;
607 }
608 }
609 } else
610#endif
611 if((((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
612 (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
613 (mCurDevice & AudioSystem::DEVICE_OUT_SPEAKER) &&
614 ((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
615 (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) ||
616 (((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
617 (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
618 (device & AudioSystem::DEVICE_OUT_SPEAKER) &&
619 ((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
620 (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)))) {
621 for(ALSAHandleList::iterator it = mDeviceList.begin();
622 it != mDeviceList.end(); ++it) {
623 if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI,
624 strlen(SND_USE_CASE_VERB_HIFI))) ||
625 (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
626 strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) {
627 mALSADevice->route(&(*it),(uint32_t)device, newMode);
628 break;
629 }
630 }
631 } else {
632 ALSAHandleList::iterator it = mDeviceList.end();
633 it--;
634 mALSADevice->route(&(*it), (uint32_t)device, newMode);
635 }
636 }
637 mCurDevice = device;
638}
639
640uint32_t AudioHardwareALSA::getVoipMode(int format)
641{
642 switch(format) {
643 case AudioSystem::PCM_16_BIT:
644 return MODE_PCM;
645 break;
646 case AudioSystem::AMR_NB:
647 return MODE_AMR;
648 break;
649 case AudioSystem::AMR_WB:
650 return MODE_AMR_WB;
651 break;
652
Ajay Dudani9746c472012-06-18 16:01:16 -0700653#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700654 case AudioSystem::EVRC:
655 return MODE_IS127;
656 break;
657
658 case AudioSystem::EVRCB:
659 return MODE_4GV_NB;
660 break;
661 case AudioSystem::EVRCWB:
662 return MODE_4GV_WB;
663 break;
Ajay Dudani9746c472012-06-18 16:01:16 -0700664#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700665
666 default:
667 return MODE_PCM;
668 }
669}
670
671AudioStreamOut *
672AudioHardwareALSA::openOutputStream(uint32_t devices,
673 int *format,
674 uint32_t *channels,
675 uint32_t *sampleRate,
676 status_t *status)
677{
678 Mutex::Autolock autoLock(mLock);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700679 ALOGD("openOutputStream: devices 0x%x channels %d sampleRate %d",
Iliyan Malchev4765c432012-06-11 14:36:16 -0700680 devices, *channels, *sampleRate);
681
682 status_t err = BAD_VALUE;
683 AudioStreamOutALSA *out = 0;
684 ALSAHandleList::iterator it;
685
686 if (devices & (devices - 1)) {
687 if (status) *status = err;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700688 ALOGE("openOutputStream called with bad devices");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700689 return out;
690 }
691# if 0
692 if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
693 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
694 bool voipstream_active = false;
695 for(it = mDeviceList.begin();
696 it != mDeviceList.end(); ++it) {
697 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
698 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700699 ALOGD("openOutput: it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700700 voipstream_active = true;
701 break;
702 }
703 }
704 if(voipstream_active == false) {
705 mVoipStreamCount = 0;
706 mVoipMicMute = false;
707 alsa_handle_t alsa_handle;
708 unsigned long bufferSize;
709 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
710 bufferSize = VOIP_BUFFER_SIZE_8K;
711 }
712 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
713 bufferSize = VOIP_BUFFER_SIZE_16K;
714 }
715 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700716 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700717 if (status) *status = err;
718 return out;
719 }
720 alsa_handle.module = mALSADevice;
721 alsa_handle.bufferSize = bufferSize;
722 alsa_handle.devices = devices;
723 alsa_handle.handle = 0;
724 if(*format == AudioSystem::PCM_16_BIT)
725 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
726 else
727 alsa_handle.format = *format;
728 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
729 alsa_handle.sampleRate = *sampleRate;
730 alsa_handle.latency = VOIP_PLAYBACK_LATENCY;
731 alsa_handle.rxHandle = 0;
732 alsa_handle.ucMgr = mUcMgr;
733 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
734 char *use_case;
735 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
736 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
737 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
738 } else {
739 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
740 }
741 free(use_case);
742 mDeviceList.push_back(alsa_handle);
743 it = mDeviceList.end();
744 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700745 ALOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipStreamCount %d mode %d", it->useCase,mCurDevice,mVoipStreamCount, mode());
Iliyan Malchev4765c432012-06-11 14:36:16 -0700746 if((mCurDevice & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
747 (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
748 (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700749 ALOGD("Routing to proxy for normal voip call in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700750 mCurDevice |= AudioSystem::DEVICE_OUT_PROXY;
751 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
752 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700753 ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700754 startUsbPlaybackIfNotStarted();
755 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700756 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700757 startUsbRecordingIfNotStarted();
758 musbRecordingState |= USBRECBIT_VOIPCALL;
759 } else{
760 mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
761 }
762 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
763 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
764 } else {
765 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
766 }
767 err = mALSADevice->startVoipCall(&(*it));
768 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700769 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700770 return NULL;
771 }
772 }
773 out = new AudioStreamOutALSA(this, &(*it));
774 err = out->set(format, channels, sampleRate, devices);
775 if(err == NO_ERROR) {
776 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -0700777 ALOGD("openoutput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700778 }
779 if (status) *status = err;
780 return out;
781 } else
782#endif
783 {
784
785 alsa_handle_t alsa_handle;
786 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
787
788 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
789 bufferSize &= ~b;
790
791 alsa_handle.module = mALSADevice;
792 alsa_handle.bufferSize = bufferSize;
793 alsa_handle.devices = devices;
794 alsa_handle.handle = 0;
795 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
796 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
797 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
798 alsa_handle.latency = PLAYBACK_LATENCY;
799 alsa_handle.rxHandle = 0;
800 alsa_handle.ucMgr = mUcMgr;
801
802 char *use_case;
803 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
804 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
805 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
806 } else {
807 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
808 }
809 free(use_case);
810 mDeviceList.push_back(alsa_handle);
811 ALSAHandleList::iterator it = mDeviceList.end();
812 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700813 ALOGD("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700814#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700815 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
816 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700817 ALOGE("Routing to proxy for normal playback in openOutputStream");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700818 devices |= AudioSystem::DEVICE_OUT_PROXY;
819 }
820#endif
821 mALSADevice->route(&(*it), devices, mode());
822 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
823 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
824 } else {
825 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
826 }
827 err = mALSADevice->open(&(*it));
828 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700829 ALOGE("Device open failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700830 } else {
831 out = new AudioStreamOutALSA(this, &(*it));
832 err = out->set(format, channels, sampleRate, devices);
833 }
834
835 if (status) *status = err;
836 return out;
837 }
838}
839
840void
841AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
842{
843 delete out;
844}
845
Ajay Dudani9746c472012-06-18 16:01:16 -0700846#ifdef QCOM_TUNNEL_LPA_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700847AudioStreamOut *
848AudioHardwareALSA::openOutputSession(uint32_t devices,
849 int *format,
850 status_t *status,
851 int sessionId,
852 uint32_t samplingRate,
853 uint32_t channels)
854{
855 Mutex::Autolock autoLock(mLock);
Iliyan Malchev4113f342012-06-11 14:39:47 -0700856 ALOGD("openOutputSession = %d" ,sessionId);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700857 AudioStreamOutALSA *out = 0;
858 status_t err = BAD_VALUE;
859
860 alsa_handle_t alsa_handle;
861 unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
862
863 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
864 bufferSize &= ~b;
865
866 alsa_handle.module = mALSADevice;
867 alsa_handle.bufferSize = bufferSize;
868 alsa_handle.devices = devices;
869 alsa_handle.handle = 0;
870 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
871 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
872 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
873 alsa_handle.latency = VOICE_LATENCY;
874 alsa_handle.rxHandle = 0;
875 alsa_handle.ucMgr = mUcMgr;
876
877 char *use_case;
878 if(sessionId == TUNNEL_SESSION_ID) {
879 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
880 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
881 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, sizeof(alsa_handle.useCase));
882 } else {
883 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, sizeof(alsa_handle.useCase));
884 }
885 } else {
886 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
887 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
888 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, sizeof(alsa_handle.useCase));
889 } else {
890 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LPA, sizeof(alsa_handle.useCase));
891 }
892 }
893 free(use_case);
894 mDeviceList.push_back(alsa_handle);
895 ALSAHandleList::iterator it = mDeviceList.end();
896 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700897 ALOGD("useCase %s", it->useCase);
Ajay Dudani9746c472012-06-18 16:01:16 -0700898#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -0700899 if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
900 (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -0700901 ALOGE("Routing to proxy for LPA in openOutputSession");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700902 devices |= AudioSystem::DEVICE_OUT_PROXY;
903 mALSADevice->route(&(*it), devices, mode());
904 devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
Iliyan Malchev4113f342012-06-11 14:39:47 -0700905 ALOGD("Starting USBPlayback for LPA");
Iliyan Malchev4765c432012-06-11 14:36:16 -0700906 startUsbPlaybackIfNotStarted();
907 musbPlaybackState |= USBPLAYBACKBIT_LPA;
908 } else
909#endif
910 {
911 mALSADevice->route(&(*it), devices, mode());
912 }
913 if(sessionId == TUNNEL_SESSION_ID) {
914 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) {
915 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_TUNNEL);
916 } else {
917 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_TUNNEL);
918 }
919 }
920 else {
921 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) {
922 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOW_POWER);
923 } else {
924 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LPA);
925 }
926 }
927 err = mALSADevice->open(&(*it));
928 out = new AudioStreamOutALSA(this, &(*it));
929
930 if (status) *status = err;
931 return out;
932}
933
934void
935AudioHardwareALSA::closeOutputSession(AudioStreamOut* out)
936{
937 delete out;
938}
Ajay Dudani9746c472012-06-18 16:01:16 -0700939#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -0700940
941AudioStreamIn *
942AudioHardwareALSA::openInputStream(uint32_t devices,
943 int *format,
944 uint32_t *channels,
945 uint32_t *sampleRate,
946 status_t *status,
947 AudioSystem::audio_in_acoustics acoustics)
948{
949 Mutex::Autolock autoLock(mLock);
950 char *use_case;
951 int newMode = mode();
952 uint32_t route_devices;
953
954 status_t err = BAD_VALUE;
955 AudioStreamInALSA *in = 0;
956 ALSAHandleList::iterator it;
957
Iliyan Malchev4113f342012-06-11 14:39:47 -0700958 ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700959 if (devices & (devices - 1)) {
960 if (status) *status = err;
961 return in;
962 }
963
964 if((devices == AudioSystem::DEVICE_IN_COMMUNICATION) &&
965 ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
966 bool voipstream_active = false;
967 for(it = mDeviceList.begin();
968 it != mDeviceList.end(); ++it) {
969 if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
970 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
Ajay Dudani9746c472012-06-18 16:01:16 -0700971 ALOGD("openInput: it->rxHandle %p it->handle %p",it->rxHandle,it->handle);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700972 voipstream_active = true;
973 break;
974 }
975 }
976 if(voipstream_active == false) {
977 mVoipStreamCount = 0;
978 mVoipMicMute = false;
979 alsa_handle_t alsa_handle;
980 unsigned long bufferSize;
981 if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
982 bufferSize = VOIP_BUFFER_SIZE_8K;
983 }
984 else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
985 bufferSize = VOIP_BUFFER_SIZE_16K;
986 }
987 else {
Iliyan Malchev4113f342012-06-11 14:39:47 -0700988 ALOGE("unsupported samplerate %d for voip",*sampleRate);
Iliyan Malchev4765c432012-06-11 14:36:16 -0700989 if (status) *status = err;
990 return in;
991 }
992 alsa_handle.module = mALSADevice;
993 alsa_handle.bufferSize = bufferSize;
994 alsa_handle.devices = devices;
995 alsa_handle.handle = 0;
996 if(*format == AudioSystem::PCM_16_BIT)
997 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
998 else
999 alsa_handle.format = *format;
1000 alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
1001 alsa_handle.sampleRate = *sampleRate;
1002 alsa_handle.latency = VOIP_RECORD_LATENCY;
1003 alsa_handle.rxHandle = 0;
1004 alsa_handle.ucMgr = mUcMgr;
1005 mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
1006 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1007 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1008 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
1009 } else {
1010 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
1011 }
1012 free(use_case);
1013 mDeviceList.push_back(alsa_handle);
1014 it = mDeviceList.end();
1015 it--;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001016 ALOGE("mCurrDevice: %d", mCurDevice);
Ajay Dudani9746c472012-06-18 16:01:16 -07001017#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001018 if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1019 (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001020 ALOGE("Routing everything from proxy for voipcall");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001021 mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
Iliyan Malchev4113f342012-06-11 14:39:47 -07001022 ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001023 startUsbPlaybackIfNotStarted();
1024 musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001025 ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001026 startUsbRecordingIfNotStarted();
1027 musbRecordingState |= USBRECBIT_VOIPCALL;
1028 }else
1029#endif
1030 {
1031 mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
1032 }
1033 if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
1034 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
1035 } else {
1036 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
1037 }
1038 if(sampleRate) {
1039 it->sampleRate = *sampleRate;
1040 }
1041 if(channels)
1042 it->channels = AudioSystem::popCount(*channels);
1043 err = mALSADevice->startVoipCall(&(*it));
1044 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001045 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001046 return NULL;
1047 }
1048 }
1049 in = new AudioStreamInALSA(this, &(*it), acoustics);
1050 err = in->set(format, channels, sampleRate, devices);
1051 if(err == NO_ERROR) {
1052 mVoipStreamCount++; //increment VoipstreamCount only if success
Iliyan Malchev4113f342012-06-11 14:39:47 -07001053 ALOGD("OpenInput mVoipStreamCount %d",mVoipStreamCount);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001054 }
Iliyan Malchev4113f342012-06-11 14:39:47 -07001055 ALOGE("openInput: After Get alsahandle");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001056 if (status) *status = err;
1057 return in;
1058 } else
1059 {
1060 for(ALSAHandleList::iterator itDev = mDeviceList.begin();
1061 itDev != mDeviceList.end(); ++itDev)
1062 {
1063 if((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_HIFI_REC, MAX_UC_LEN))
1064 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, MAX_UC_LEN))
1065 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_FM, MAX_UC_LEN))
Ajay Dudani9746c472012-06-18 16:01:16 -07001066#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001067 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_REC, MAX_UC_LEN))
1068#endif
1069 )
1070 {
Ajay Dudani9746c472012-06-18 16:01:16 -07001071#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001072 if(!(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001073 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001074 itDev->useCase, itDev->devices, itDev->module);
1075 return in;
1076 }
1077#endif
1078 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001079#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001080 else if ((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, MAX_UC_LEN))
1081 ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, MAX_UC_LEN)))
1082 {
1083 if((devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001084 ALOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
Iliyan Malchev4765c432012-06-11 14:36:16 -07001085 itDev->useCase, itDev->devices, itDev->module);
1086 return in;
1087 }
1088 }
1089#endif
1090 }
1091
1092 alsa_handle_t alsa_handle;
1093 unsigned long bufferSize = DEFAULT_IN_BUFFER_SIZE;
1094
1095 alsa_handle.module = mALSADevice;
1096 alsa_handle.bufferSize = bufferSize;
1097 alsa_handle.devices = devices;
1098 alsa_handle.handle = 0;
1099 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1100 alsa_handle.channels = VOICE_CHANNEL_MODE;
1101 alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
1102 alsa_handle.latency = RECORD_LATENCY;
1103 alsa_handle.rxHandle = 0;
1104 alsa_handle.ucMgr = mUcMgr;
1105 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1106 if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1107 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1108 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001109 ALOGD("openInputStream: into incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001110 mIncallMode = *channels;
1111 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1112 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1113 if (mFusion3Platform) {
1114 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1115 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1116 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001117 } else {
1118 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
1119 sizeof(alsa_handle.useCase));
1120 }
1121 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1122 if (mFusion3Platform) {
1123 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1124 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
1125 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001126 } else {
1127 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
1128 sizeof(alsa_handle.useCase));
1129 }
1130 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001131#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001132 } else if((devices == AudioSystem::DEVICE_IN_FM_RX)) {
1133 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(alsa_handle.useCase));
1134 } else if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1135 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
1136#endif
1137 } else {
1138 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(alsa_handle.useCase));
1139 }
1140 } else {
1141 if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
1142 (newMode == AudioSystem::MODE_IN_CALL)) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001143 ALOGD("openInputStream: incall recording, channels %d", *channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001144 mIncallMode = *channels;
1145 if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
1146 (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
1147 if (mFusion3Platform) {
1148 mALSADevice->setVocRecMode(INCALL_REC_STEREO);
1149 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1150 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001151 } else {
1152 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
1153 sizeof(alsa_handle.useCase));
1154 }
1155 } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
1156 if (mFusion3Platform) {
1157 mALSADevice->setVocRecMode(INCALL_REC_MONO);
1158 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
1159 sizeof(alsa_handle.useCase));
Iliyan Malchev4765c432012-06-11 14:36:16 -07001160 } else {
1161 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
1162 sizeof(alsa_handle.useCase));
1163 }
1164 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001165#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001166 } else if(devices == AudioSystem::DEVICE_IN_FM_RX) {
1167 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_REC, sizeof(alsa_handle.useCase));
1168 } else if (devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
1169 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(alsa_handle.useCase));
1170#endif
1171 } else {
1172 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
1173 }
1174 }
1175 free(use_case);
1176 mDeviceList.push_back(alsa_handle);
1177 ALSAHandleList::iterator it = mDeviceList.end();
1178 it--;
1179 //update channel info before do routing
1180 if(channels) {
1181 it->channels = AudioSystem::popCount((*channels) &
Ajay Dudani9746c472012-06-18 16:01:16 -07001182 (AudioSystem::CHANNEL_IN_STEREO
1183 | AudioSystem::CHANNEL_IN_MONO
1184#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001185 | AudioSystem::CHANNEL_IN_5POINT1
1186#endif
1187 ));
Iliyan Malchev4113f342012-06-11 14:39:47 -07001188 ALOGV("updated channel info: channels=%d", it->channels);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001189 }
1190 if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
1191 /* Add current devices info to devices to do route */
Ajay Dudani9746c472012-06-18 16:01:16 -07001192#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001193 if(mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
1194 mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001195 ALOGD("Routing everything from proxy for VOIP call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001196 route_devices = devices | AudioSystem::DEVICE_IN_PROXY;
1197 } else
1198#endif
1199 {
1200 route_devices = devices | mCurDevice;
1201 }
1202 mALSADevice->route(&(*it), route_devices, mode());
1203 } else {
Ajay Dudani9746c472012-06-18 16:01:16 -07001204#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001205 if(devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET ||
1206 devices & AudioSystem::DEVICE_IN_PROXY) {
1207 devices |= AudioSystem::DEVICE_IN_PROXY;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001208 ALOGE("routing everything from proxy");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001209 mALSADevice->route(&(*it), devices, mode());
1210 } else
1211#endif
1212 {
1213 mALSADevice->route(&(*it), devices, mode());
1214 }
1215 }
1216
1217 if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
Ajay Dudani9746c472012-06-18 16:01:16 -07001218#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001219 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) ||
1220 !strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
1221#endif
1222 !strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) ||
1223 !strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
1224 !strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
1225 snd_use_case_set(mUcMgr, "_verb", it->useCase);
1226 } else {
1227 snd_use_case_set(mUcMgr, "_enamod", it->useCase);
1228 }
1229 if(sampleRate) {
1230 it->sampleRate = *sampleRate;
1231 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001232#ifdef QCOM_SSR_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001233 if (6 == it->channels) {
1234 if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
1235 || !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001236 ALOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001237 it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
1238 }
1239 }
1240#endif
1241 err = mALSADevice->open(&(*it));
1242 if (err) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001243 ALOGE("Error opening pcm input device");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001244 } else {
1245 in = new AudioStreamInALSA(this, &(*it), acoustics);
1246 err = in->set(format, channels, sampleRate, devices);
1247 }
1248 if (status) *status = err;
1249 return in;
1250 }
1251}
1252
1253void
1254AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
1255{
1256 delete in;
1257}
1258
1259status_t AudioHardwareALSA::setMicMute(bool state)
1260{
1261 int newMode = mode();
Iliyan Malchev4113f342012-06-11 14:39:47 -07001262 ALOGD("setMicMute newMode %d",newMode);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001263 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1264 if (mVoipMicMute != state) {
1265 mVoipMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001266 ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001267 if(mALSADevice) {
1268 mALSADevice->setVoipMicMute(state);
1269 }
1270 }
1271 } else {
1272 if (mMicMute != state) {
1273 mMicMute = state;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001274 ALOGD("setMicMute: mMicMute %d", mMicMute);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001275 if(mALSADevice) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001276 if(mCSCallActive == CS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001277 mALSADevice->setMicMute(state);
Ajay Dudani9746c472012-06-18 16:01:16 -07001278 if(mVolteCallActive == IMS_ACTIVE)
Iliyan Malchev4765c432012-06-11 14:36:16 -07001279 mALSADevice->setVoLTEMicMute(state);
1280 }
1281 }
1282 }
1283 return NO_ERROR;
1284}
1285
1286status_t AudioHardwareALSA::getMicMute(bool *state)
1287{
1288 int newMode = mode();
1289 if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
1290 *state = mVoipMicMute;
1291 } else {
1292 *state = mMicMute;
1293 }
1294 return NO_ERROR;
1295}
1296
1297status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
1298{
1299 return NO_ERROR;
1300}
1301
1302size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
1303{
1304 size_t bufferSize;
1305 if (format != AudioSystem::PCM_16_BIT
1306 && format != AudioSystem::AMR_NB
1307 && format != AudioSystem::AMR_WB
Ajay Dudani9746c472012-06-18 16:01:16 -07001308#ifdef QCOM_QCHAT_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001309 && format != AudioSystem::EVRC
1310 && format != AudioSystem::EVRCB
Ajay Dudani9746c472012-06-18 16:01:16 -07001311 && format != AudioSystem::EVRCWB
1312#endif
1313 ) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001314 ALOGW("getInputBufferSize bad format: %d", format);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001315 return 0;
1316 }
1317 if(sampleRate == 16000) {
1318 bufferSize = DEFAULT_IN_BUFFER_SIZE * 2 * channelCount;
1319 } else if(sampleRate < 44100) {
1320 bufferSize = DEFAULT_IN_BUFFER_SIZE * channelCount;
1321 } else {
1322 bufferSize = DEFAULT_IN_BUFFER_SIZE * 12;
1323 }
1324 return bufferSize;
1325}
1326
Ajay Dudani9746c472012-06-18 16:01:16 -07001327#ifdef QCOM_FM_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001328void AudioHardwareALSA::handleFm(int device)
1329{
1330int newMode = mode();
1331 if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
1332 // Start FM Radio on current active device
1333 unsigned long bufferSize = FM_BUFFER_SIZE;
1334 alsa_handle_t alsa_handle;
1335 char *use_case;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001336 ALOGV("Start FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001337 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1338 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1339 strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DIGITAL_RADIO, sizeof(alsa_handle.useCase));
1340 } else {
1341 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_FM, sizeof(alsa_handle.useCase));
1342 }
1343 free(use_case);
1344
1345 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1346 bufferSize &= ~b;
1347 alsa_handle.module = mALSADevice;
1348 alsa_handle.bufferSize = bufferSize;
1349 alsa_handle.devices = device;
1350 alsa_handle.handle = 0;
1351 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1352 alsa_handle.channels = DEFAULT_CHANNEL_MODE;
1353 alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
1354 alsa_handle.latency = VOICE_LATENCY;
1355 alsa_handle.rxHandle = 0;
1356 alsa_handle.ucMgr = mUcMgr;
1357 mIsFmActive = 1;
1358 mDeviceList.push_back(alsa_handle);
1359 ALSAHandleList::iterator it = mDeviceList.end();
1360 it--;
1361 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1362 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1363 device |= AudioSystem::DEVICE_OUT_PROXY;
1364 alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
Iliyan Malchev4113f342012-06-11 14:39:47 -07001365 ALOGE("Routing to proxy for FM case");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001366 }
1367 mALSADevice->route(&(*it), (uint32_t)device, newMode);
1368 if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) {
1369 snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_DIGITAL_RADIO);
1370 } else {
1371 snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
1372 }
1373 mALSADevice->startFm(&(*it));
1374 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1375 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
Iliyan Malchev4113f342012-06-11 14:39:47 -07001376 ALOGE("Starting FM, musbPlaybackState %d", musbPlaybackState);
Iliyan Malchev4765c432012-06-11 14:36:16 -07001377 startUsbPlaybackIfNotStarted();
1378 musbPlaybackState |= USBPLAYBACKBIT_FM;
1379 }
1380 } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
1381 //i Stop FM Radio
Iliyan Malchev4113f342012-06-11 14:39:47 -07001382 ALOGV("Stop FM");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001383 for(ALSAHandleList::iterator it = mDeviceList.begin();
1384 it != mDeviceList.end(); ++it) {
1385 if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
1386 (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
1387 mALSADevice->close(&(*it));
1388 //mALSADevice->route(&(*it), (uint32_t)device, newMode);
1389 mDeviceList.erase(it);
1390 break;
1391 }
1392 }
1393 mIsFmActive = 0;
1394 musbPlaybackState &= ~USBPLAYBACKBIT_FM;
1395 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1396 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1397 closeUsbPlaybackIfNothingActive();
1398 }
1399 }
1400}
1401#endif
1402
1403void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, int device)
1404{
1405 for(ALSAHandleList::iterator it = mDeviceList.begin();
1406 it != mDeviceList.end(); ++it) {
1407 if((!strcmp(it->useCase, verb)) ||
1408 (!strcmp(it->useCase, modifier))) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001409 ALOGV("Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001410 mALSADevice->close(&(*it));
1411 mALSADevice->route(&(*it), (uint32_t)device, mode);
1412 mDeviceList.erase(it);
1413 break;
1414 }
1415 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001416#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001417 if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001418 ALOGE("Voice call ended on USB");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001419 musbPlaybackState &= ~USBPLAYBACKBIT_VOICECALL;
1420 musbRecordingState &= ~USBRECBIT_VOICECALL;
1421 closeUsbRecordingIfNothingActive();
1422 closeUsbPlaybackIfNothingActive();
1423 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001424#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001425}
1426void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, int device)
1427{
1428// Start voice call
1429unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
1430alsa_handle_t alsa_handle;
1431char *use_case;
1432 snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
1433 if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
1434 strlcpy(alsa_handle.useCase, verb, sizeof(alsa_handle.useCase));
1435 } else {
1436 strlcpy(alsa_handle.useCase, modifier, sizeof(alsa_handle.useCase));
1437 }
1438 free(use_case);
1439
1440 for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
1441 bufferSize &= ~b;
1442 alsa_handle.module = mALSADevice;
1443 alsa_handle.bufferSize = bufferSize;
1444 alsa_handle.devices = device;
1445 alsa_handle.handle = 0;
1446 alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
1447 alsa_handle.channels = VOICE_CHANNEL_MODE;
1448 alsa_handle.sampleRate = VOICE_SAMPLING_RATE;
1449 alsa_handle.latency = VOICE_LATENCY;
1450 alsa_handle.rxHandle = 0;
1451 alsa_handle.ucMgr = mUcMgr;
1452 mDeviceList.push_back(alsa_handle);
1453 ALSAHandleList::iterator it = mDeviceList.end();
1454 it--;
Ajay Dudani9746c472012-06-18 16:01:16 -07001455#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001456 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1457 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1458 device |= AudioSystem::DEVICE_OUT_PROXY;
1459 alsa_handle.devices = device;
1460 }
1461#endif
1462 mALSADevice->route(&(*it), (uint32_t)device, mode);
1463 if (!strcmp(it->useCase, verb)) {
1464 snd_use_case_set(mUcMgr, "_verb", verb);
1465 } else {
1466 snd_use_case_set(mUcMgr, "_enamod", modifier);
1467 }
1468 mALSADevice->startVoiceCall(&(*it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001469#ifdef QCOM_USBAUDIO_ENABLED
Iliyan Malchev4765c432012-06-11 14:36:16 -07001470 if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
1471 (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
1472 startUsbRecordingIfNotStarted();
1473 startUsbPlaybackIfNotStarted();
1474 musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
1475 musbRecordingState |= USBRECBIT_VOICECALL;
1476 }
Ajay Dudani9746c472012-06-18 16:01:16 -07001477#endif
Iliyan Malchev4765c432012-06-11 14:36:16 -07001478}
1479
1480bool AudioHardwareALSA::routeVoiceCall(int device, int newMode)
1481{
1482int csCallState = mCallState&0xF;
1483 bool isRouted = false;
1484 switch (csCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001485 case CS_INACTIVE:
1486 if (mCSCallActive != CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001487 ALOGD("doRouting: Disabling voice call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001488 disableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1489 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1490 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001491 mCSCallActive = CS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001492 }
1493 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001494 case CS_ACTIVE:
1495 if (mCSCallActive == CS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001496 ALOGD("doRouting: Enabling CS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001497 enableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
1498 (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
1499 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001500 mCSCallActive = CS_ACTIVE;
1501 } else if (mCSCallActive == CS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001502 ALOGD("doRouting: Resume voice call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001503 ALSAHandleList::iterator vt_it;
1504 for(vt_it = mDeviceList.begin();
1505 vt_it != mDeviceList.end(); ++vt_it) {
1506 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1507 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1508 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1509 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
1510 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001511 mCSCallActive = CS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001512 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001513 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001514 break;
1515 }
1516 }
1517 }
1518 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001519 case CS_HOLD:
1520 if (mCSCallActive == CS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001521 ALOGD("doRouting: Voice call going to Hold");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001522 ALSAHandleList::iterator vt_it;
1523 for(vt_it = mDeviceList.begin();
1524 vt_it != mDeviceList.end(); ++vt_it) {
1525 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOICECALL,
1526 strlen(SND_USE_CASE_VERB_VOICECALL))) ||
1527 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
1528 strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001529 mCSCallActive = CS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001530 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1531 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001532 ALOGE("Voice pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001533 break;
1534 }
1535 }
1536 }
1537 break;
1538 }
1539 return isRouted;
1540}
1541bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
1542{
1543int volteCallState = mCallState&0xF0;
1544bool isRouted = false;
1545switch (volteCallState) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001546 case IMS_INACTIVE:
1547 if (mVolteCallActive != IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001548 ALOGD("doRouting: Disabling IMS call");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001549 disableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1550 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1551 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001552 mVolteCallActive = IMS_INACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001553 }
1554 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001555 case IMS_ACTIVE:
1556 if (mVolteCallActive == IMS_INACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001557 ALOGD("doRouting: Enabling IMS voice call ");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001558 enableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
1559 (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
1560 isRouted = true;
Ajay Dudani9746c472012-06-18 16:01:16 -07001561 mVolteCallActive = IMS_ACTIVE;
1562 } else if (mVolteCallActive == IMS_HOLD) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001563 ALOGD("doRouting: Resume IMS call from hold state");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001564 ALSAHandleList::iterator vt_it;
1565 for(vt_it = mDeviceList.begin();
1566 vt_it != mDeviceList.end(); ++vt_it) {
1567 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1568 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1569 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1570 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
1571 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
Ajay Dudani9746c472012-06-18 16:01:16 -07001572 mVolteCallActive = IMS_ACTIVE;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001573 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001574 ALOGE("VoLTE resume failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001575 break;
1576 }
1577 }
1578 }
1579 break;
Ajay Dudani9746c472012-06-18 16:01:16 -07001580 case IMS_HOLD:
1581 if (mVolteCallActive == IMS_ACTIVE) {
Iliyan Malchev4113f342012-06-11 14:39:47 -07001582 ALOGD("doRouting: IMS ACTIVE going to HOLD");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001583 ALSAHandleList::iterator vt_it;
1584 for(vt_it = mDeviceList.begin();
1585 vt_it != mDeviceList.end(); ++vt_it) {
1586 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_VOLTE,
1587 strlen(SND_USE_CASE_VERB_VOLTE))) ||
1588 (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
1589 strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
Ajay Dudani9746c472012-06-18 16:01:16 -07001590 mVolteCallActive = IMS_HOLD;
Iliyan Malchev4765c432012-06-11 14:36:16 -07001591 alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
1592 if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
Iliyan Malchev4113f342012-06-11 14:39:47 -07001593 ALOGE("VoLTE Pause failed");
Iliyan Malchev4765c432012-06-11 14:36:16 -07001594 break;
1595 }
1596 }
1597 }
1598 break;
1599 }
1600 return isRouted;
1601}
1602
1603} // namespace android_audio_legacy